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

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1989-1993  Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     connect.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains code which performs the following TDI services:
        !            12: 
        !            13:         o   TdiAccept
        !            14:         o   TdiListen
        !            15:         o   TdiConnect
        !            16:         o   TdiDisconnect
        !            17:         o   TdiAssociateAddress
        !            18:         o   TdiDisassociateAddress
        !            19:         o   OpenConnection
        !            20:         o   CloseConnection
        !            21: 
        !            22: Environment:
        !            23: 
        !            24:     Kernel mode
        !            25: 
        !            26: Revision History:
        !            27: 
        !            28: --*/
        !            29: 
        !            30: #include "st.h"
        !            31: 
        !            32: 
        !            33: NTSTATUS
        !            34: StTdiAccept(
        !            35:     IN PIRP Irp
        !            36:     )
        !            37: 
        !            38: /*++
        !            39: 
        !            40: Routine Description:
        !            41: 
        !            42:     This routine performs the TdiAccept request for the transport provider.
        !            43: 
        !            44: Arguments:
        !            45: 
        !            46:     Irp - Pointer to the I/O Request Packet for this request.
        !            47: 
        !            48: Return Value:
        !            49: 
        !            50:     NTSTATUS - status of operation.
        !            51: 
        !            52: --*/
        !            53: 
        !            54: {
        !            55:     PTP_CONNECTION connection;
        !            56:     PIO_STACK_LOCATION irpSp;
        !            57:     KIRQL oldirql;
        !            58:     NTSTATUS status;
        !            59: 
        !            60:     //
        !            61:     // Get the connection this is associated with; if there is none, get out.
        !            62:     //
        !            63: 
        !            64:     irpSp = IoGetCurrentIrpStackLocation (Irp);
        !            65: 
        !            66:     connection  = irpSp->FileObject->FsContext;
        !            67: 
        !            68:     //
        !            69:     // This adds a connection reference if successful.
        !            70:     //
        !            71: 
        !            72:     status = StVerifyConnectionObject (connection);
        !            73: 
        !            74:     if (!NT_SUCCESS (status)) {
        !            75:         return status;
        !            76:     }
        !            77: 
        !            78:     //
        !            79:     // just set the connection flags to allow reads and writes to proceed.
        !            80:     //
        !            81: 
        !            82:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !            83: 
        !            84:     //
        !            85:     // Turn off the stopping flag for this connection.
        !            86:     //
        !            87: 
        !            88:     connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
        !            89:     connection->Status = STATUS_PENDING;
        !            90: 
        !            91:     connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
        !            92: 
        !            93: 
        !            94:     if (connection->AddressFile->ConnectIndicationInProgress) {
        !            95:         connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
        !            96:     }
        !            97: 
        !            98:     if ((connection->Flags2 & CONNECTION_FLAGS2_WAIT_ACCEPT) != 0) {
        !            99: 
        !           100:         //
        !           101:         // We previously completed a listen, now the user is
        !           102:         // coming back with an accept, Set this flag to allow
        !           103:         // the connection to proceed.
        !           104:         //
        !           105: 
        !           106:         connection->Flags |= CONNECTION_FLAGS_READY;
        !           107: 
        !           108:         INCREMENT_COUNTER (connection->Provider, OpenConnections);
        !           109: 
        !           110:         //
        !           111:         // Set this flag to enable disconnect indications; once
        !           112:         // the client has accepted he expects those.
        !           113:         //
        !           114: 
        !           115:         connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_ACCEPT;
        !           116:         connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
        !           117: 
        !           118:         StReferenceConnection("Pended listen completed", connection);
        !           119: 
        !           120:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           121: 
        !           122:     } else {
        !           123: 
        !           124:         //
        !           125:         // This accept is being called at some point before
        !           126:         // the link is up; directly from the connection handler
        !           127:         // or at some point slightly later.
        !           128:         //
        !           129: 
        !           130:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           131: 
        !           132:     }
        !           133: 
        !           134:     StDereferenceConnection ("Temp TdiAccept", connection);
        !           135: 
        !           136:     return STATUS_SUCCESS;
        !           137: 
        !           138: } /* StTdiAccept */
        !           139: 
        !           140: 
        !           141: NTSTATUS
        !           142: StTdiAssociateAddress(
        !           143:     IN PIRP Irp
        !           144:     )
        !           145: 
        !           146: /*++
        !           147: 
        !           148: Routine Description:
        !           149: 
        !           150:     This routine performs the association of the connection and the address for
        !           151:     the user.
        !           152: 
        !           153: Arguments:
        !           154: 
        !           155:     Irp - Pointer to the I/O Request Packet for this request.
        !           156: 
        !           157: Return Value:
        !           158: 
        !           159:     NTSTATUS - status of operation.
        !           160: 
        !           161: --*/
        !           162: 
        !           163: {
        !           164:     NTSTATUS status;
        !           165:     PFILE_OBJECT fileObject;
        !           166:     PTP_ADDRESS_FILE addressFile;
        !           167:     PTP_ADDRESS oldAddress;
        !           168:     PTP_CONNECTION connection;
        !           169:     PIO_STACK_LOCATION irpSp;
        !           170:     PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
        !           171:     PDEVICE_CONTEXT deviceContext;
        !           172: 
        !           173:     KIRQL oldirql, oldirql2;
        !           174: 
        !           175:     irpSp = IoGetCurrentIrpStackLocation (Irp);
        !           176: 
        !           177:     //
        !           178:     // verify that the operation is taking place on a connection. At the same
        !           179:     // time we do this, we reference the connection. This ensures it does not
        !           180:     // get removed out from under us. Note also that we do the connection
        !           181:     // lookup within a try/except clause, thus protecting ourselves against
        !           182:     // really bogus handles
        !           183:     //
        !           184: 
        !           185:     connection  = irpSp->FileObject->FsContext;
        !           186:     status = StVerifyConnectionObject (connection);
        !           187:     if (!NT_SUCCESS (status)) {
        !           188:         return status;
        !           189:     }
        !           190: 
        !           191: 
        !           192:     //
        !           193:     // Make sure this connection is ready to be associated.
        !           194:     //
        !           195: 
        !           196:     oldAddress = (PTP_ADDRESS)NULL;
        !           197: 
        !           198:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
        !           199: 
        !           200:     if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
        !           201:         ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
        !           202: 
        !           203:         //
        !           204:         // The connection is already associated with
        !           205:         // an active connection...bad!
        !           206:         //
        !           207: 
        !           208:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
        !           209:         StDereferenceConnection ("Temp Ref Associate", connection);
        !           210: 
        !           211:         return STATUS_INVALID_CONNECTION;
        !           212: 
        !           213:     } else {
        !           214: 
        !           215:         //
        !           216:         // See if there is an old association hanging around...
        !           217:         // this happens if the connection has been disassociated,
        !           218:         // but not closed.
        !           219:         //
        !           220: 
        !           221:         if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) {
        !           222: 
        !           223:             //
        !           224:             // Save this; since it is non-null this address
        !           225:             // will be dereferenced after the connection
        !           226:             // spinlock is released.
        !           227:             //
        !           228: 
        !           229:             oldAddress = connection->AddressFile->Address;
        !           230: 
        !           231:             //
        !           232:             // Remove the old association.
        !           233:             //
        !           234: 
        !           235:             connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
        !           236:             RemoveEntryList (&connection->AddressList);
        !           237:             RemoveEntryList (&connection->AddressFileList);
        !           238:             InitializeListHead (&connection->AddressList);
        !           239:             InitializeListHead (&connection->AddressFileList);
        !           240:             connection->AddressFile = NULL;
        !           241: 
        !           242:         }
        !           243: 
        !           244:     }
        !           245: 
        !           246:     RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
        !           247: 
        !           248:     //
        !           249:     // If we removed an old association, dereference the
        !           250:     // address.
        !           251:     //
        !           252: 
        !           253:     if (oldAddress != (PTP_ADDRESS)NULL) {
        !           254: 
        !           255:         StDereferenceAddress("Removed old association", oldAddress);
        !           256: 
        !           257:     }
        !           258: 
        !           259: 
        !           260:     deviceContext = connection->Provider;
        !           261: 
        !           262:     parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
        !           263: 
        !           264:     //
        !           265:     // get a pointer to the address File Object, which points us to the
        !           266:     // transport's address object, which is where we want to put the
        !           267:     // connection.
        !           268:     //
        !           269: 
        !           270:     status = ObReferenceObjectByHandle (
        !           271:                 parameters->AddressHandle,
        !           272:                 0L,
        !           273:                 0,
        !           274:                 KernelMode,
        !           275:                 (PVOID *) &fileObject,
        !           276:                 NULL);
        !           277: 
        !           278:     if (NT_SUCCESS(status)) {
        !           279: 
        !           280:         //
        !           281:         // we might have one of our address objects; verify that.
        !           282:         //
        !           283: 
        !           284:         addressFile = fileObject->FsContext;
        !           285: 
        !           286:         if (NT_SUCCESS (StVerifyAddressObject (addressFile))) {
        !           287: 
        !           288:             //
        !           289:             // have an address and connection object. Add the connection to the
        !           290:             // address object database. Also add the connection to the address
        !           291:             // file object db (used primarily for cleaning up). Reference the
        !           292:             // address to account for one more reason for it staying open.
        !           293:             //
        !           294: 
        !           295:             ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
        !           296:             if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
        !           297: 
        !           298:                 ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
        !           299: 
        !           300:                 if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
        !           301: 
        !           302:                     StReferenceAddress (
        !           303:                         "Connection associated",
        !           304:                         addressFile->Address);
        !           305: 
        !           306:                     InsertTailList (
        !           307:                         &addressFile->Address->ConnectionDatabase,
        !           308:                         &connection->AddressList);
        !           309: 
        !           310:                     InsertTailList (
        !           311:                         &addressFile->ConnectionDatabase,
        !           312:                         &connection->AddressFileList);
        !           313: 
        !           314:                     connection->AddressFile = addressFile;
        !           315:                     connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED;
        !           316:                     connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED;
        !           317: 
        !           318:                     if (addressFile->ConnectIndicationInProgress) {
        !           319:                         connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
        !           320:                     }
        !           321: 
        !           322:                     status = STATUS_SUCCESS;
        !           323: 
        !           324:                 } else {
        !           325: 
        !           326:                     //
        !           327:                     // The connection is closing, stop the
        !           328:                     // association.
        !           329:                     //
        !           330: 
        !           331:                     status = STATUS_INVALID_CONNECTION;
        !           332: 
        !           333:                 }
        !           334: 
        !           335:                 RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
        !           336: 
        !           337:             } else {
        !           338: 
        !           339:                 status = STATUS_INVALID_HANDLE;
        !           340:             }
        !           341: 
        !           342:             RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
        !           343: 
        !           344:             StDereferenceAddress ("Temp associate", addressFile->Address);
        !           345: 
        !           346:         } else {
        !           347: 
        !           348:             status = STATUS_INVALID_HANDLE;
        !           349:         }
        !           350: 
        !           351:         //
        !           352:         // Note that we don't keep a reference to this file object around.
        !           353:         // That's because the IO subsystem manages the object for us; we simply
        !           354:         // want to keep the association. We only use this association when the
        !           355:         // IO subsystem has asked us to close one of the file object, and then
        !           356:         // we simply remove the association.
        !           357:         //
        !           358: 
        !           359:         ObDereferenceObject (fileObject);
        !           360: 
        !           361:     } else {
        !           362:         status = STATUS_INVALID_HANDLE;
        !           363:     }
        !           364: 
        !           365:     StDereferenceConnection ("Temp Ref Associate", connection);
        !           366: 
        !           367:     return status;
        !           368: 
        !           369: } /* TdiAssociateAddress */
        !           370: 
        !           371: 
        !           372: NTSTATUS
        !           373: StTdiDisassociateAddress(
        !           374:     IN PIRP Irp
        !           375:     )
        !           376: /*++
        !           377: 
        !           378: Routine Description:
        !           379: 
        !           380:     This routine performs the disassociation of the connection and the address
        !           381:     for the user. If the connection has not been stopped, it will be stopped
        !           382:     here.
        !           383: 
        !           384: Arguments:
        !           385: 
        !           386:     Irp - Pointer to the I/O Request Packet for this request.
        !           387: 
        !           388: Return Value:
        !           389: 
        !           390:     NTSTATUS - status of operation.
        !           391: 
        !           392: --*/
        !           393: 
        !           394: {
        !           395: 
        !           396:     KIRQL oldirql;
        !           397:     PIO_STACK_LOCATION irpSp;
        !           398:     PTP_CONNECTION connection;
        !           399:     NTSTATUS status;
        !           400: 
        !           401:     irpSp = IoGetCurrentIrpStackLocation (Irp);
        !           402: 
        !           403:     connection  = irpSp->FileObject->FsContext;
        !           404: 
        !           405:     //
        !           406:     // If successful this adds a reference.
        !           407:     //
        !           408: 
        !           409:     status = StVerifyConnectionObject (connection);
        !           410: 
        !           411:     if (!NT_SUCCESS (status)) {
        !           412:         return status;
        !           413:     }
        !           414: 
        !           415:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !           416:     if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
        !           417:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           418:         StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
        !           419: 
        !           420:     } else {
        !           421:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           422:     }
        !           423: 
        !           424:     //
        !           425:     // and now we disassociate the address. This only removes
        !           426:     // the appropriate reference for the connection, the
        !           427:     // actually disassociation will be done later.
        !           428:     //
        !           429:     // The DISASSOCIATED flag is used to make sure that
        !           430:     // only one person removes this reference.
        !           431:     //
        !           432: 
        !           433:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !           434:     if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
        !           435:             ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
        !           436:         connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
        !           437:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           438:     } else {
        !           439:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           440:     }
        !           441: 
        !           442:     StDereferenceConnection ("Temp use in Associate", connection);
        !           443: 
        !           444:     return STATUS_SUCCESS;
        !           445: 
        !           446: } /* TdiDisassociateAddress */
        !           447: 
        !           448: 
        !           449: NTSTATUS
        !           450: StTdiConnect(
        !           451:     IN PIRP Irp
        !           452:     )
        !           453: 
        !           454: /*++
        !           455: 
        !           456: Routine Description:
        !           457: 
        !           458:     This routine performs the TdiConnect request for the transport provider.
        !           459: 
        !           460: Arguments:
        !           461: 
        !           462:     Irp - Pointer to the I/O Request Packet for this request.
        !           463: 
        !           464: Return Value:
        !           465: 
        !           466:     NTSTATUS - status of operation.
        !           467: 
        !           468: --*/
        !           469: 
        !           470: {
        !           471:     NTSTATUS status;
        !           472:     PTP_CONNECTION connection;
        !           473:     PSTRING GeneralBroadcastSourceRoute = NULL; // BUGBUG: define this later.
        !           474:     LARGE_INTEGER timeout = {0,0};
        !           475:     KIRQL oldirql, cancelirql;
        !           476:     PTP_REQUEST tpRequest;
        !           477:     PIO_STACK_LOCATION irpSp;
        !           478:     PTDI_REQUEST_KERNEL parameters;
        !           479:     PTA_NETBIOS_ADDRESS RemoteAddress;
        !           480:     ULONG RemoteAddressLength;
        !           481: 
        !           482:     //
        !           483:     // is the file object a connection?
        !           484:     //
        !           485: 
        !           486:     irpSp = IoGetCurrentIrpStackLocation (Irp);
        !           487:     connection  = irpSp->FileObject->FsContext;
        !           488: 
        !           489:     //
        !           490:     // If successful this adds a reference.
        !           491:     //
        !           492: 
        !           493:     status = StVerifyConnectionObject (connection);
        !           494: 
        !           495:     if (!NT_SUCCESS (status)) {
        !           496:         return status;
        !           497:     }
        !           498: 
        !           499:     parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
        !           500: 
        !           501:     //
        !           502:     // fix up the timeout if required; no connect request should take more
        !           503:     // than 15 seconds if there is someone out there. We'll assume that's
        !           504:     // what the user wanted if they specify -1 as the timer length.
        !           505:     //
        !           506: 
        !           507:     if (parameters->RequestSpecific != NULL) {
        !           508:         if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
        !           509:              (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
        !           510: 
        !           511:             timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L);    // n * 10 ** 7 => 100ns units
        !           512:             if (timeout.LowPart != 0) {
        !           513:                 timeout.HighPart = -1L;
        !           514:             } else {
        !           515:                 timeout.HighPart = 0;
        !           516:             }
        !           517: 
        !           518:         } else {
        !           519: 
        !           520:             timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
        !           521:             timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
        !           522:         }
        !           523:     }
        !           524: 
        !           525:     //
        !           526:     // Check that the remote is a Netbios address.
        !           527:     //
        !           528: 
        !           529:     RemoteAddress = (PTA_NETBIOS_ADDRESS)
        !           530:                       (parameters->RequestConnectionInformation->RemoteAddress);
        !           531: 
        !           532:     if (RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS) {
        !           533: 
        !           534:         StDereferenceConnection ("Not Netbios", connection);
        !           535:         return STATUS_BAD_NETWORK_PATH;           // don't even try to find it.
        !           536: 
        !           537:     }
        !           538: 
        !           539:     //
        !           540:     // copy the called address someplace we can use it.
        !           541:     //
        !           542: 
        !           543:     RemoteAddressLength = parameters->RequestConnectionInformation->RemoteAddressLength;
        !           544: 
        !           545:     if (RemoteAddressLength > sizeof(TA_NETBIOS_ADDRESS)) {
        !           546:         RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
        !           547:     }
        !           548: 
        !           549:     RtlCopyMemory(
        !           550:         connection->CalledAddress.NetbiosName,
        !           551:         RemoteAddress->Address[0].Address[0].NetbiosName,
        !           552:         16);
        !           553: 
        !           554:     //
        !           555:     // We need a request object to keep track of this TDI request.
        !           556:     // Attach this request to the new connection object.
        !           557:     //
        !           558: 
        !           559:     status = StCreateRequest (
        !           560:                  Irp,                           // IRP for this request.
        !           561:                  connection,                    // context.
        !           562:                  REQUEST_FLAGS_CONNECTION,      // partial flags.
        !           563:                  NULL,
        !           564:                  0,
        !           565:                  timeout,
        !           566:                  &tpRequest);
        !           567: 
        !           568:     if (!NT_SUCCESS (status)) {                    // couldn't make the request.
        !           569:         StDereferenceConnection ("Throw away", connection);
        !           570:         return status;                          // return with failure.
        !           571:     } else {
        !           572: 
        !           573:         // Reference the connection since StDestroyRequest derefs it.
        !           574: 
        !           575:         StReferenceConnection("For connect request", connection);
        !           576: 
        !           577:         tpRequest->Owner = ConnectionType;
        !           578:         IoAcquireCancelSpinLock (&cancelirql);
        !           579:         ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
        !           580:         if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
        !           581:             RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
        !           582:             IoReleaseCancelSpinLock (cancelirql);
        !           583:             StCompleteRequest (
        !           584:                 tpRequest,
        !           585:                 connection->Status,
        !           586:                 0);
        !           587:             StDereferenceConnection("Temporary Use 1", connection);
        !           588:             return STATUS_PENDING;
        !           589:         } else {
        !           590:             InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
        !           591: 
        !           592:             connection->Flags |= CONNECTION_FLAGS_CONNECTOR;   // we're the initiator.
        !           593: 
        !           594:             connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
        !           595:             connection->Status = STATUS_PENDING;
        !           596: 
        !           597:             connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
        !           598:             RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
        !           599: 
        !           600:             //
        !           601:             // Check if the IRP has been cancelled.
        !           602:             //
        !           603: 
        !           604:             if (Irp->Cancel) {
        !           605:                 Irp->CancelIrql = cancelirql;
        !           606:                 StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
        !           607:                 StDereferenceConnection ("IRP cancelled", connection);   // release lookup hold.
        !           608:                 return STATUS_PENDING;
        !           609:             }
        !           610: 
        !           611:             Irp->CancelRoutine = StCancelConnection;
        !           612:             IoReleaseCancelSpinLock(cancelirql);
        !           613: 
        !           614:         }
        !           615:     }
        !           616: 
        !           617:     status = StSendConnect (
        !           618:                 connection);
        !           619: 
        !           620:     if (!NT_SUCCESS(status)) {                    // can't send the name request
        !           621:         StStopConnection (connection, status);
        !           622:         StDereferenceConnection("Temporary Use 2", connection);
        !           623: 
        !           624:         //
        !           625:         // Note that this return status isn't really a lie. We are waiting
        !           626:         // for the connection to run down.
        !           627:         //
        !           628: 
        !           629:         return STATUS_PENDING;
        !           630:     }
        !           631: 
        !           632: 
        !           633:     StDereferenceConnection("Temporary Use 3", connection);
        !           634: 
        !           635:     return STATUS_PENDING;                      // things are started.
        !           636: 
        !           637: } /* TdiConnect */
        !           638: 
        !           639: 
        !           640: NTSTATUS
        !           641: StTdiDisconnect(
        !           642:     IN PIRP Irp
        !           643:     )
        !           644: 
        !           645: /*++
        !           646: 
        !           647: Routine Description:
        !           648: 
        !           649:     This routine performs the TdiDisconnect request for the transport provider.
        !           650: 
        !           651: Arguments:
        !           652: 
        !           653:     Irp - Pointer to the I/O Request Packet for this request.
        !           654: 
        !           655: Return Value:
        !           656: 
        !           657:     NTSTATUS - status of operation.
        !           658: 
        !           659: --*/
        !           660: 
        !           661: {
        !           662:     PTP_CONNECTION connection;
        !           663:     LARGE_INTEGER timeout;
        !           664:     PIO_STACK_LOCATION irpSp;
        !           665:     PTDI_REQUEST_KERNEL parameters;
        !           666:     KIRQL oldirql;
        !           667:     NTSTATUS status;
        !           668: 
        !           669: 
        !           670:     irpSp = IoGetCurrentIrpStackLocation (Irp);
        !           671: 
        !           672:     connection  = irpSp->FileObject->FsContext;
        !           673: 
        !           674:     //
        !           675:     // If successful this adds a reference.
        !           676:     //
        !           677: 
        !           678:     status = StVerifyConnectionObject (connection);
        !           679:     if (!NT_SUCCESS (status)) {
        !           680:         return status;
        !           681:     }
        !           682: 
        !           683: 
        !           684:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !           685: 
        !           686:     //
        !           687:     // if the connection is currently stopping, there's no reason to blow
        !           688:     // it away...
        !           689:     //
        !           690: 
        !           691:     if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
        !           692: 
        !           693:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           694:         StDereferenceConnection ("Ignoring disconnect", connection);       // release our lookup reference.
        !           695:         return connection->Status;
        !           696: 
        !           697:     } else {
        !           698:         connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
        !           699:                                  CONNECTION_FLAGS2_PRE_ACCEPT |
        !           700:                                  CONNECTION_FLAGS2_WAIT_ACCEPT);
        !           701:         connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
        !           702: 
        !           703:         //
        !           704:         // Set this flag so the disconnect IRP is completed.
        !           705:         //
        !           706:         // BUGBUG: If the connection goes down before we can
        !           707:         // call StStopConnection with STATUS_LOCAL_DISCONNECT,
        !           708:         // the disconnect IRP won't get completed.
        !           709:         //
        !           710: 
        !           711:         connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
        !           712: 
        !           713:         connection->DisconnectIrp = Irp;
        !           714:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !           715:     }
        !           716: 
        !           717:     //
        !           718:     // fix up the timeout if required; no disconnect request should take very
        !           719:     // long. However, the user can cause the timeout to not happen if they
        !           720:     // desire that.
        !           721:     //
        !           722: 
        !           723:     parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
        !           724: 
        !           725:     //
        !           726:     // fix up the timeout if required; no disconnect request should take more
        !           727:     // than 15 seconds. We'll assume that's what the user wanted if they
        !           728:     // specify -1 as the timer.
        !           729:     //
        !           730: 
        !           731:     if (parameters->RequestSpecific != NULL) {
        !           732:         if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
        !           733:              (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
        !           734: 
        !           735:             timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L);    // n * 10 ** 7 => 100ns units
        !           736:             if (timeout.LowPart != 0) {
        !           737:                 timeout.HighPart = -1L;
        !           738:             } else {
        !           739:                 timeout.HighPart = 0;
        !           740:             }
        !           741: 
        !           742:         } else {
        !           743:             timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
        !           744:             timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
        !           745:         }
        !           746:     }
        !           747: 
        !           748:     //
        !           749:     // Now the reason for the disconnect
        !           750:     //
        !           751: 
        !           752:     if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) {
        !           753:         connection->Flags |= CONNECTION_FLAGS_DESTROY;
        !           754:     } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
        !           755:         connection->Flags |= CONNECTION_FLAGS_ABORT;
        !           756:     } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
        !           757:         connection->Flags |= CONNECTION_FLAGS_ORDREL;
        !           758:     }
        !           759: 
        !           760:     //
        !           761:     // This will get passed to IoCompleteRequest during TdiDestroyConnection
        !           762:     //
        !           763: 
        !           764:     StStopConnection (connection, STATUS_LOCAL_DISCONNECT);              // starts the abort sequence.
        !           765:     StDereferenceConnection ("Disconnecting", connection);       // release our lookup reference.
        !           766: 
        !           767:     //
        !           768:     // This request will be completed by TdiDestroyConnection once
        !           769:     // the connection reference count drops to 0.
        !           770:     //
        !           771: 
        !           772:     return STATUS_PENDING;
        !           773: } /* TdiDisconnect */
        !           774: 
        !           775: 
        !           776: NTSTATUS
        !           777: StTdiListen(
        !           778:     IN PIRP Irp
        !           779:     )
        !           780: 
        !           781: /*++
        !           782: 
        !           783: Routine Description:
        !           784: 
        !           785:     This routine performs the TdiListen request for the transport provider.
        !           786: 
        !           787: Arguments:
        !           788: 
        !           789:     Irp - Pointer to the I/O Request Packet for this request.
        !           790: 
        !           791: Return Value:
        !           792: 
        !           793:     NTSTATUS - status of operation.
        !           794: 
        !           795: --*/
        !           796: 
        !           797: {
        !           798:     NTSTATUS status;
        !           799:     PTP_CONNECTION connection;
        !           800:     LARGE_INTEGER timeout = {0,0};
        !           801:     KIRQL oldirql, cancelirql;
        !           802:     PTP_REQUEST tpRequest;
        !           803:     PIO_STACK_LOCATION irpSp;
        !           804:     PTDI_REQUEST_KERNEL_LISTEN parameters;
        !           805: 
        !           806:     //
        !           807:     // validate this connection
        !           808: 
        !           809:     irpSp = IoGetCurrentIrpStackLocation (Irp);
        !           810: 
        !           811:     connection  = irpSp->FileObject->FsContext;
        !           812: 
        !           813:     //
        !           814:     // If successful this adds a reference.
        !           815:     //
        !           816: 
        !           817:     status = StVerifyConnectionObject (connection);
        !           818: 
        !           819:     if (!NT_SUCCESS (status)) {
        !           820:         return status;
        !           821:     }
        !           822: 
        !           823:     parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
        !           824: 
        !           825:     //
        !           826:     // We need a request object to keep track of this TDI request.
        !           827:     // Attach this request to the new connection object.
        !           828:     //
        !           829: 
        !           830:     status = StCreateRequest (
        !           831:                  Irp,                           // IRP for this request.
        !           832:                  connection,                    // context.
        !           833:                  REQUEST_FLAGS_CONNECTION,      // partial flags.
        !           834:                  NULL,
        !           835:                  0,
        !           836:                  timeout,                       // timeout value (can be 0).
        !           837:                  &tpRequest);
        !           838: 
        !           839: 
        !           840:     if (!NT_SUCCESS (status)) {                    // couldn't make the request.
        !           841: 
        !           842:         StDereferenceConnection ("For create", connection);
        !           843:         return status;                          // return with failure.
        !           844:     }
        !           845: 
        !           846:     // Reference the connection since StDestroyRequest derefs it.
        !           847: 
        !           848:     IoAcquireCancelSpinLock (&cancelirql);
        !           849:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !           850:     tpRequest->Owner = ConnectionType;
        !           851: 
        !           852:     StReferenceConnection("For listen request", connection);
        !           853: 
        !           854:     if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
        !           855: 
        !           856:         RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
        !           857:         IoReleaseCancelSpinLock(cancelirql);
        !           858: 
        !           859:         StCompleteRequest (
        !           860:             tpRequest,
        !           861:             connection->Status,
        !           862:             0);
        !           863:         StDereferenceConnection("Temp create", connection);
        !           864:         return STATUS_PENDING;
        !           865: 
        !           866:     } else {
        !           867: 
        !           868:         InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
        !           869:         connection->Flags |= CONNECTION_FLAGS_LISTENER |     // we're the passive one.
        !           870:                              CONNECTION_FLAGS_WAIT_LISTEN;   // waiting for a connect
        !           871:         connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
        !           872:         connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
        !           873:         connection->Status = STATUS_PENDING;
        !           874: 
        !           875:         //
        !           876:         // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to
        !           877:         // indicate that when the listen completes we do not have to
        !           878:         // wait for a TDI_ACCEPT to continue.
        !           879:         //
        !           880: 
        !           881:         if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) {
        !           882:             connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT;
        !           883:         }
        !           884: 
        !           885:         RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
        !           886: 
        !           887:         //
        !           888:         // Check if the IRP has been cancelled.
        !           889:         //
        !           890: 
        !           891:         if (Irp->Cancel) {
        !           892:             Irp->CancelIrql = cancelirql;
        !           893:             StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
        !           894:             StDereferenceConnection ("IRP cancelled", connection);   // release lookup hold.
        !           895:             return STATUS_PENDING;
        !           896:         }
        !           897: 
        !           898:         Irp->CancelRoutine = StCancelConnection;
        !           899:         IoReleaseCancelSpinLock(cancelirql);
        !           900: 
        !           901:     }
        !           902: 
        !           903:     //
        !           904:     // Wait for an incoming NAME_QUERY frame.  The remainder of the
        !           905:     // connectionless protocol to set up a connection is processed
        !           906:     // in the NAME_QUERY frame handler.
        !           907:     //
        !           908: 
        !           909:     StDereferenceConnection("Temp create", connection);
        !           910: 
        !           911:     return STATUS_PENDING;                      // things are started.
        !           912: } /* TdiListen */
        !           913: 
        !           914: 
        !           915: NTSTATUS
        !           916: StOpenConnection (
        !           917:     IN PDEVICE_OBJECT DeviceObject,
        !           918:     IN PIRP Irp,
        !           919:     IN PIO_STACK_LOCATION IrpSp
        !           920:     )
        !           921: 
        !           922: /*++
        !           923: 
        !           924: Routine Description:
        !           925: 
        !           926:     This routine is called to open a connection. Note that the connection that
        !           927:     is open is of little use until associated with an address; until then,
        !           928:     the only thing that can be done with it is close it.
        !           929: 
        !           930: Arguments:
        !           931: 
        !           932:     DeviceObject - Pointer to the device object for this driver.
        !           933: 
        !           934:     Irp - Pointer to the request packet representing the I/O request.
        !           935: 
        !           936:     IrpSp - Pointer to current IRP stack frame.
        !           937: 
        !           938: Return Value:
        !           939: 
        !           940:     The function value is the status of the operation.
        !           941: 
        !           942: --*/
        !           943: 
        !           944: {
        !           945:     PDEVICE_CONTEXT DeviceContext;
        !           946:     NTSTATUS status;
        !           947:     PTP_CONNECTION connection;
        !           948:     PFILE_FULL_EA_INFORMATION ea;
        !           949: 
        !           950:     UNREFERENCED_PARAMETER (Irp);
        !           951: 
        !           952:     DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
        !           953: 
        !           954:     //
        !           955:     // First, try to make a connection object to represent this pending
        !           956:     // connection.  Then fill in the relevant fields.
        !           957:     // In addition to the creation, if successful StCreateConnection
        !           958:     // will create a second reference which is removed once the request
        !           959:     // references the connection, or if the function exits before that.
        !           960: 
        !           961:     status = StCreateConnection (DeviceContext, &connection);
        !           962:     if (!NT_SUCCESS (status)) {
        !           963:         return status;                          // sorry, we couldn't make one.
        !           964:     }
        !           965: 
        !           966:     //
        !           967:     // set the connection context so we can connect the user to this data
        !           968:     // structure
        !           969:     //
        !           970: 
        !           971:     ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
        !           972:     RtlCopyMemory (
        !           973:         &connection->Context,
        !           974:         &ea->EaName[ea->EaNameLength+1],
        !           975:         sizeof (PVOID));
        !           976: 
        !           977:     //
        !           978:     // let file object point at connection and connection at file object
        !           979:     //
        !           980: 
        !           981:     IrpSp->FileObject->FsContext = (PVOID)connection;
        !           982:     IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
        !           983:     connection->FileObject = IrpSp->FileObject;
        !           984: 
        !           985:     return status;
        !           986: 
        !           987: } /* StOpenConnection */
        !           988: 
        !           989: 
        !           990: NTSTATUS
        !           991: StCloseConnection (
        !           992:     IN PDEVICE_OBJECT DeviceObject,
        !           993:     IN PIRP Irp,
        !           994:     IN PIO_STACK_LOCATION IrpSp
        !           995:     )
        !           996: 
        !           997: /*++
        !           998: 
        !           999: Routine Description:
        !          1000: 
        !          1001:     This routine is called to close a connection. There may be actions in
        !          1002:     progress on this connection, so we note the closing IRP, mark the
        !          1003:     connection as closing, and complete it somewhere down the road (when all
        !          1004:     references have been removed).
        !          1005: 
        !          1006: Arguments:
        !          1007: 
        !          1008:     DeviceObject - Pointer to the device object for this driver.
        !          1009: 
        !          1010:     Irp - Pointer to the request packet representing the I/O request.
        !          1011: 
        !          1012:     IrpSp - Pointer to current IRP stack frame.
        !          1013: 
        !          1014: Return Value:
        !          1015: 
        !          1016:     The function value is the status of the operation.
        !          1017: 
        !          1018: --*/
        !          1019: 
        !          1020: {
        !          1021:     NTSTATUS status;
        !          1022:     KIRQL oldirql;
        !          1023:     PTP_CONNECTION connection;
        !          1024: 
        !          1025:     UNREFERENCED_PARAMETER (DeviceObject);
        !          1026:     UNREFERENCED_PARAMETER (Irp);
        !          1027: 
        !          1028:     //
        !          1029:     // is the file object a connection?
        !          1030:     //
        !          1031: 
        !          1032:     connection  = IrpSp->FileObject->FsContext;
        !          1033: 
        !          1034: 
        !          1035:     //
        !          1036:     // We duplicate the code from VerifyConnectionObject,
        !          1037:     // although we don't actually call that since it does
        !          1038:     // a reference, which we don't want (to avoid bouncing
        !          1039:     // the reference count up from 0 if this is a dead
        !          1040:     // link).
        !          1041:     //
        !          1042: 
        !          1043:     try {
        !          1044: 
        !          1045:         if ((connection->Size == sizeof (TP_CONNECTION)) &&
        !          1046:             (connection->Type == ST_CONNECTION_SIGNATURE)) {
        !          1047: 
        !          1048:             ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !          1049: 
        !          1050:             if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
        !          1051: 
        !          1052:                 status = STATUS_SUCCESS;
        !          1053: 
        !          1054:             } else {
        !          1055: 
        !          1056:                 status = STATUS_INVALID_CONNECTION;
        !          1057:             }
        !          1058: 
        !          1059:             RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !          1060: 
        !          1061:         } else {
        !          1062: 
        !          1063:             status = STATUS_INVALID_CONNECTION;
        !          1064:         }
        !          1065: 
        !          1066:     } except(EXCEPTION_EXECUTE_HANDLER) {
        !          1067: 
        !          1068:          return GetExceptionCode();
        !          1069:     }
        !          1070: 
        !          1071:     if (!NT_SUCCESS (status)) {
        !          1072:         return status;
        !          1073:     }
        !          1074: 
        !          1075:     //
        !          1076:     // We recognize it; is it closing already?
        !          1077:     //
        !          1078: 
        !          1079:     ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !          1080: 
        !          1081:     if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
        !          1082:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !          1083:         StDereferenceConnection("Temp Close", connection);
        !          1084:         return STATUS_INVALID_CONNECTION;
        !          1085:     }
        !          1086: 
        !          1087:     connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
        !          1088: 
        !          1089:     //
        !          1090:     // if there is activity on the connection, tear it down.
        !          1091:     //
        !          1092: 
        !          1093:     if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
        !          1094:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !          1095:         StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
        !          1096:         ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
        !          1097:     }
        !          1098: 
        !          1099:     //
        !          1100:     // If the connection is still associated, disassociate it.
        !          1101:     //
        !          1102: 
        !          1103:     if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
        !          1104:             ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
        !          1105:         connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
        !          1106:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !          1107:     } else {
        !          1108:         RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
        !          1109:     }
        !          1110: 
        !          1111: 
        !          1112:     //
        !          1113:     // Save this to complete the IRP later.
        !          1114:     //
        !          1115: 
        !          1116:     connection->CloseIrp = Irp;
        !          1117: 
        !          1118:     //
        !          1119:     // make it impossible to use this connection from the file object
        !          1120:     //
        !          1121: 
        !          1122:     IrpSp->FileObject->FsContext = NULL;
        !          1123:     IrpSp->FileObject->FsContext2 = NULL;
        !          1124:     connection->FileObject = NULL;
        !          1125: 
        !          1126:     //
        !          1127:     // dereference for the creation. Note that this dereference
        !          1128:     // here won't have any effect until the regular reference count
        !          1129:     // hits zero.
        !          1130:     //
        !          1131: 
        !          1132:     StDereferenceConnectionSpecial (" Closing Connection", connection);
        !          1133: 
        !          1134:     return STATUS_PENDING;
        !          1135: 
        !          1136: } /* StCloseConnection */
        !          1137: 

unix.superglobalmegacorp.com

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