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