Annotation of ntddk/src/network/tdi/sendeng.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1989-1993  Microsoft Corporation
                      4: 
                      5: Module Name:
                      6: 
                      7:     sendeng.c
                      8: 
                      9: Abstract:
                     10: 
                     11:     This module contains code that implements the send engine for the
                     12:     Sample transport provider.
                     13: 
                     14: Environment:
                     15: 
                     16:     Kernel mode
                     17: 
                     18: Revision History:
                     19: 
                     20: 
                     21: --*/
                     22: 
                     23: #include "st.h"
                     24: #if 27
                     25: ULONG StNoisySend = 0;
                     26: ULONG StSndLoc = 0;
                     27: ULONG StSnds[10];
                     28: #endif
                     29: 
                     30: 
                     31: VOID
                     32: StartPacketizingConnection(
                     33:     PTP_CONNECTION Connection,
                     34:     IN BOOLEAN Immediate,
                     35:     IN KIRQL ConnectionIrql,
                     36:     IN KIRQL CancelIrql
                     37:     )
                     38: 
                     39: /*++
                     40: 
                     41: Routine Description:
                     42: 
                     43:     This routine is called to place a connection on the PacketizeQueue
                     44:     of its device context object.  Then this routine starts packetizing
                     45:     the first connection on that queue.
                     46: 
                     47:     *** The Connection spin lock must be held on entry to this routine.
                     48:         Optionally, the cancel spin lock may be held.  If so, the cancel
                     49:         spin lock must have been acquired first.
                     50: 
                     51: Arguments:
                     52: 
                     53:     Connection - Pointer to a TP_CONNECTION object.
                     54: 
                     55:     Immediate - TRUE if the connection should be packetized
                     56:         immediately; FALSE if the connection should be queued
                     57:         up for later packetizing (implies that ReceiveComplete
                     58:         will be called in the future, which packetizes always).
                     59: 
                     60:         NOTE: If this is TRUE, it also implies that we have
                     61:         a connection reference.
                     62: 
                     63:     ConnectionIrql - The OldIrql value when the connection spin lock
                     64:         was acquired.
                     65: 
                     66:     CancelIrql - The OldIrql value when the cancel spin lock was
                     67:         acquired.  -1 means that the cancel spin lock isn't held.
                     68: 
                     69: Return Value:
                     70: 
                     71:     none.
                     72: 
                     73: --*/
                     74: 
                     75: {
                     76:     PDEVICE_CONTEXT DeviceContext;
                     77: 
                     78:     DeviceContext = Connection->Provider;
                     79: 
                     80:     //
                     81:     // If this connection's SendState is set to PACKETIZE and if
                     82:     // we are not already on the PacketizeQueue, then go ahead and
                     83:     // append us to the end of that queue, and remember that we're
                     84:     // on it by setting the CONNECTION_FLAGS_PACKETIZE bitflag.
                     85:     //
                     86:     // Also don't queue it if the connection is stopping.
                     87:     //
                     88: 
                     89:     if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
                     90:         !(Connection->Flags &
                     91:             (CONNECTION_FLAGS_PACKETIZE | CONNECTION_FLAGS_STOPPING))) {
                     92: 
                     93:         Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
                     94: 
                     95:         if (!Immediate) {
                     96:             StReferenceConnection ("Packetize", Connection);
                     97:         }
                     98: 
                     99:         ExInterlockedInsertTailList(
                    100:             &DeviceContext->PacketizeQueue,
                    101:             &Connection->PacketizeLinkage,
                    102:             &DeviceContext->SpinLock);
                    103: 
                    104:         RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql);
                    105: 
                    106:     } else {
                    107: 
                    108:         RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql);
                    109:         if (Immediate) {
                    110:             StDereferenceConnection("temp TdiSend", Connection);
                    111:         }
                    112:     }
                    113: 
                    114:     if (CancelIrql != (KIRQL)-1) {
                    115:         IoReleaseCancelSpinLock (CancelIrql);
                    116:     }
                    117: 
                    118:     if (Immediate) {
                    119:         PacketizeConnections (DeviceContext);
                    120:     }
                    121: 
                    122: } /* StartPacketizingConnection */
                    123: 
                    124: 
                    125: VOID
                    126: PacketizeConnections(
                    127:     PDEVICE_CONTEXT DeviceContext
                    128:     )
                    129: 
                    130: /*++
                    131: 
                    132: Routine Description:
                    133: 
                    134:     This routine attempts to packetize all connections waiting on the
                    135:     PacketizeQueue of the DeviceContext.
                    136: 
                    137: 
                    138: Arguments:
                    139: 
                    140:     DeviceContext - Pointer to a DEVICE_CONTEXT object.
                    141: 
                    142: Return Value:
                    143: 
                    144:     none.
                    145: 
                    146: --*/
                    147: 
                    148: {
                    149:     PLIST_ENTRY p;
                    150:     PTP_CONNECTION Connection;
                    151: 
                    152:     //
                    153:     // Pick connections off of the device context's packetization queue
                    154:     // until there are no more left to pick off.  For each one, we call
                    155:     // PacketizeSend.  Note this routine can be executed concurrently
                    156:     // on multiple processors and it doesn't matter; multiple connections
                    157:     // may be packetized concurrently.
                    158:     //
                    159: 
                    160:     while (TRUE) {
                    161: 
                    162:         p = ExInterlockedRemoveHeadList(
                    163:             &DeviceContext->PacketizeQueue,
                    164:             &DeviceContext->SpinLock);
                    165: 
                    166:         if (p == NULL) {
                    167:             break;
                    168:         }
                    169:         Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
                    170:         PacketizeSend (Connection);
                    171:     }
                    172: 
                    173: } /* PacketizeConnections */
                    174: 
                    175: 
                    176: VOID
                    177: PacketizeSend(
                    178:     PTP_CONNECTION Connection
                    179:     )
                    180: 
                    181: /*++
                    182: 
                    183: Routine Description:
                    184: 
                    185:     This routine packetizes the current TdiSend request on the specified
                    186:     connection as much as limits will permit.  A given here is that there
                    187:     is an active send on the connection that needs further packetization.
                    188: 
                    189: Arguments:
                    190: 
                    191:     Connection - Pointer to a TP_CONNECTION object.
                    192: 
                    193: Return Value:
                    194: 
                    195:     none.
                    196: 
                    197: --*/
                    198: 
                    199: {
                    200:     KIRQL oldirql, oldirql1;
                    201:     ULONG MaxFrameSize, FrameSize;
                    202:     ULONG PacketBytes;
                    203:     TP_SEND_POINTER SavedSendPointer;
                    204:     PNDIS_BUFFER PacketDescriptor;
                    205:     PUCHAR SourceRouting;
                    206:     UINT SourceRoutingLength;
                    207:     PDEVICE_CONTEXT DeviceContext;
                    208:     PTP_PACKET Packet;
                    209:     NTSTATUS Status;
                    210:     PST_HEADER StHeader;
                    211:     UINT HeaderLength;
                    212:     PIO_STACK_LOCATION IrpSp;
                    213:     PSEND_PACKET_TAG SendTag;
                    214:     ULONG LastPacketLength;
                    215: 
                    216:     DeviceContext = Connection->Provider;
                    217: 
                    218:     //
                    219:     // Just loop until one of three events happens: (1) we run out of
                    220:     // packets from StCreatePacket, (2) we completely packetize the send.
                    221:     //
                    222: 
                    223:     ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    224: 
                    225:     if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
                    226:         Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
                    227:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    228:         StDereferenceConnection ("No longer packetizing", Connection);
                    229:         return;
                    230:     }
                    231: 
                    232:     MaxFrameSize = Connection->MaximumDataSize;
                    233: 
                    234:     //
                    235:     // It is possible for a frame to arrive during the middle of this loop
                    236:     // (such as a NO_RECEIVE) that will put us into a new state (such as
                    237:     // W_RCVCONT).  For this reason, we have to check the state every time
                    238:     // (at the end of the loop).
                    239:     //
                    240: 
                    241:     do {
                    242: 
                    243:         if (!NT_SUCCESS (StCreatePacket (DeviceContext, &Packet))) {
                    244: 
                    245:             //
                    246:             // We need a packet to finish packetizing the current send, but
                    247:             // there are no more packets available in the pool right now.
                    248:             // Set our send state to W_PACKET, and put this connection on
                    249:             // the PacketWaitQueue of the device context object.  Then,
                    250:             // when StDestroyPacket frees up a packet, it will check this
                    251:             // queue for starved connections, and if it finds one, it will
                    252:             // take a connection off the list and set its send state to
                    253:             // SENDSTATE_PACKETIZE and put it on the PacketizeQueue.
                    254:             //
                    255: 
                    256:             Connection->SendState = CONNECTION_SENDSTATE_W_PACKET;
                    257: 
                    258:             //
                    259:             // Clear the PACKETIZE flag, indicating that we're no longer
                    260:             // on the PacketizeQueue or actively packetizing.  The flag
                    261:             // was set by StartPacketizingConnection to indicate that
                    262:             // the connection was already on the PacketizeQueue.
                    263:             //
                    264:             // Don't queue him if the connection is stopping.
                    265:             //
                    266: 
                    267:             Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
                    268: 
                    269:             if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) {
                    270:                 Connection->Flags |= CONNECTION_FLAGS_SUSPENDED;
                    271:                 ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
                    272:                 InsertTailList (&DeviceContext->PacketWaitQueue, &Connection->PacketWaitLinkage);
                    273:                 RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
                    274:             }
                    275: 
                    276:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    277:             StDereferenceConnection ("No packet", Connection);
                    278:             return;
                    279: 
                    280:         }
                    281: 
                    282:         //
                    283:         // Add a reference count to the IRP, and keep track of
                    284:         // which request it is. Send completion will remove the
                    285:         // reference.
                    286: 
                    287:         IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp);
                    288: 
                    289:         SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
                    290:         SendTag->Type = TYPE_I_FRAME;
                    291:         SendTag->Packet = Packet;
                    292:         SendTag->Owner = (PVOID)IrpSp;
                    293: 
                    294:         Packet->CompleteSend = FALSE;
                    295: 
                    296: 
                    297:         //
                    298:         // Build the MAC header. All frames go out as
                    299:         // single-route source routing.
                    300:         //
                    301: 
                    302: 
                    303:         MacReturnSingleRouteSR(
                    304:             &DeviceContext->MacInfo,
                    305:             &SourceRouting,
                    306:             &SourceRoutingLength);
                    307: 
                    308:         MacConstructHeader (
                    309:             &DeviceContext->MacInfo,
                    310:             Packet->Header,
                    311:             DeviceContext->MulticastAddress.Address,
                    312:             DeviceContext->LocalAddress.Address,
                    313:             sizeof(ST_HEADER),
                    314:             SourceRouting,
                    315:             SourceRoutingLength,
                    316:             &HeaderLength);
                    317: 
                    318:         //
                    319:         // Build the header: 'I', dest, source
                    320:         //
                    321: 
                    322:         StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
                    323: 
                    324:         StHeader->Signature = ST_SIGNATURE;
                    325:         StHeader->Command = ST_CMD_INFORMATION;
                    326:         StHeader->Flags = 0;
                    327: 
                    328:         RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
                    329:         RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
                    330: 
                    331:         HeaderLength += sizeof(ST_HEADER);
                    332: 
                    333: 
                    334:         //
                    335:         // Modify the packet length and send the it.
                    336:         //
                    337: 
                    338:         StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
                    339: 
                    340:         StReferenceSendIrp ("Packetize", IrpSp);
                    341: 
                    342:         //
                    343:         // Save our complex send pointer in case we have to restore it
                    344:         // because StNdisSend fails.
                    345:         //
                    346: 
                    347:         SavedSendPointer = Connection->sp;
                    348: 
                    349:         //
                    350:         // build an NDIS_BUFFER chain that describes the buffer we're using, and
                    351:         // thread it off the NdisBuffer. This chain may not complete the
                    352:         // packet, as the remaining part of the MDL chain may be shorter than
                    353:         // the packet.
                    354:         //
                    355: 
                    356:         FrameSize = MaxFrameSize;
                    357: 
                    358:         //
                    359:         // Check if we have less than FrameSize left to send.
                    360:         //
                    361: 
                    362:         if (Connection->sp.MessageBytesSent + FrameSize > Connection->CurrentSendLength) {
                    363: 
                    364:             FrameSize = Connection->CurrentSendLength - Connection->sp.MessageBytesSent;
                    365: 
                    366:         }
                    367: #if 27
                    368:         if (StNoisySend) {
                    369:             DbgPrint ("Send %d of %d\n", FrameSize, Connection->CurrentSendLength);
                    370:         }
                    371:         if (FrameSize > 1000) {
                    372:             StSnds[StSndLoc] = FrameSize;
                    373:             StSndLoc = (StSndLoc + 1) % 10;
                    374:         }
                    375: #endif
                    376: 
                    377: 
                    378:         //
                    379:         // Make a copy of the MDL chain for this send, unless
                    380:         // there are zero bytes left.
                    381:         //
                    382: 
                    383:         if (FrameSize != 0) {
                    384: 
                    385:             //
                    386:             // If the whole send will fit inside one packet,
                    387:             // then there is no need to duplicate the MDL
                    388:             // (note that this may include multi-MDL sends).
                    389:             //
                    390: 
                    391:             if ((Connection->sp.SendByteOffset == 0) &&
                    392:                 (Connection->CurrentSendLength == FrameSize)) {
                    393: 
                    394:                 PacketDescriptor = (PNDIS_BUFFER)Connection->sp.CurrentSendMdl;
                    395:                 PacketBytes = FrameSize;
                    396:                 Connection->sp.CurrentSendMdl = NULL;
                    397:                 Connection->sp.SendByteOffset = FrameSize;
                    398:                 Packet->PacketNoNdisBuffer = TRUE;
                    399:                 Status = STATUS_SUCCESS;
                    400: 
                    401:             } else {
                    402: 
                    403:                 Status = BuildBufferChainFromMdlChain (
                    404:                             DeviceContext->NdisBufferPoolHandle,
                    405:                             Connection->sp.CurrentSendMdl,
                    406:                             Connection->sp.SendByteOffset,
                    407:                             FrameSize,
                    408:                             &PacketDescriptor,
                    409:                             &Connection->sp.CurrentSendMdl,
                    410:                             &Connection->sp.SendByteOffset,
                    411:                             &PacketBytes);
                    412: 
                    413:             }
                    414: 
                    415:         } else {
                    416: 
                    417:             PacketBytes = 0;
                    418:             Connection->sp.CurrentSendMdl = NULL;
                    419:             Status = STATUS_SUCCESS;
                    420: 
                    421:         }
                    422: 
                    423:         if (NT_SUCCESS (Status)) {
                    424: 
                    425:             Connection->sp.MessageBytesSent += PacketBytes;
                    426: 
                    427:             //
                    428:             // Chain the buffers to the packet, unless there
                    429:             // are zero bytes of data.
                    430:             //
                    431: 
                    432:             if (FrameSize != 0) {
                    433:                 NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor);
                    434:             }
                    435: 
                    436: 
                    437:             //
                    438:             // Have we run out of Mdl Chain in this request?
                    439:             //
                    440: 
                    441:             if ((PacketBytes < FrameSize) ||
                    442:                     (Connection->sp.CurrentSendMdl == NULL) ||
                    443:                     (Connection->CurrentSendLength <= Connection->sp.MessageBytesSent)) {
                    444: 
                    445:                 //
                    446:                 // Yep. We know that we've exhausted the current request's buffer
                    447:                 // here, so see if there's another request without EOF set that we
                    448:                 // can build start throwing into this packet.
                    449:                 //
                    450: 
                    451: 
                    452:                 if (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) {
                    453: 
                    454:                     //
                    455:                     // We are sending the last packet in a message.  Change
                    456:                     // the packet type to a "last" frame.
                    457:                     //
                    458: 
                    459:                     StHeader->Flags |= ST_FLAGS_LAST;
                    460:                     Packet->CompleteSend = TRUE;
                    461:                     Connection->SendState = CONNECTION_SENDSTATE_IDLE;
                    462: 
                    463:                 } else {
                    464: 
                    465:                     //
                    466:                     // We are sending the last packet in this request. If there
                    467:                     // are more requests in the connection's SendQueue, then
                    468:                     // advance complex send pointer to point to the next one
                    469:                     // in line.  Otherwise, if there aren't any more requests
                    470:                     // ready to packetize, then we enter the W_EOR state and
                    471:                     // stop packetizing. Note that we're waiting here for the TDI
                    472:                     // client to come up with data to send; we're just hanging out
                    473:                     // until then.
                    474:                     //
                    475: 
                    476:                     if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) {
                    477: 
                    478:                         Connection->SendState = CONNECTION_SENDSTATE_W_EOR;
                    479: 
                    480:                     } else {
                    481: 
                    482:                         Connection->sp.CurrentSendIrp =
                    483:                             CONTAINING_RECORD (
                    484:                                 Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink,
                    485:                                 IRP,
                    486:                                 Tail.Overlay.ListEntry);
                    487:                         Connection->sp.CurrentSendMdl =
                    488:                             Connection->sp.CurrentSendIrp->MdlAddress;
                    489:                         Connection->sp.SendByteOffset = 0;
                    490:                         Connection->CurrentSendLength +=
                    491:                             IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
                    492:                     }
                    493:                 }
                    494:             }
                    495: 
                    496:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    497: 
                    498:             LastPacketLength = sizeof(ST_HEADER) + PacketBytes;
                    499: 
                    500:             MacModifyHeader(
                    501:                  &DeviceContext->MacInfo,
                    502:                  Packet->Header,
                    503:                  LastPacketLength);
                    504: 
                    505:             Packet->NdisIFrameLength = LastPacketLength;
                    506: 
                    507:             StNdisSend (Packet);
                    508: 
                    509:             //
                    510:             // Update our counters (this is done unprotected by a lock).
                    511:             //
                    512: 
                    513:             ADD_TO_LARGE_INTEGER(
                    514:                 &DeviceContext->IFrameBytesSent,
                    515:                 PacketBytes,
                    516:                 &DeviceContext->StatisticsSpinLock);
                    517:             ++DeviceContext->IFramesSent;
                    518: 
                    519:         } else {
                    520: 
                    521:             //
                    522:             // BuildBufferChainFromMdlChain failed; we need to
                    523:             // release the lock since the long if() above
                    524:             // exits with it released.
                    525:             //
                    526: 
                    527:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    528: 
                    529:         }
                    530: 
                    531:         //
                    532:         // Note that we may have fallen out of the BuildBuffer... if above with
                    533:         // Status set to STATUS_INSUFFICIENT_RESOURCES. if we have, we'll just
                    534:         // stick this connection back onto the packetize queue and hope the
                    535:         // system gets more resources later.
                    536:         //
                    537: 
                    538: 
                    539:         if (!NT_SUCCESS (Status)) {
                    540: 
                    541:             ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    542: 
                    543:             //
                    544:             // Restore old complex send pointer.
                    545:             //
                    546: 
                    547:             Connection->sp = SavedSendPointer;
                    548: 
                    549: 
                    550:             //
                    551:             // Indicate we're waiting on favorable link conditions.
                    552:             //
                    553: 
                    554:             Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
                    555: 
                    556:             //
                    557:             // Clear the PACKETIZE flag, indicating that we're no longer
                    558:             // on the PacketizeQueue or actively packetizing.  The flag
                    559:             // was set by StartPacketizingConnection to indicate that
                    560:             // the connection was already on the PacketizeQueue.
                    561:             //
                    562: 
                    563:             Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
                    564: 
                    565:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    566: 
                    567:             StDestroyPacket (Packet);
                    568:             StDereferenceSendIrp("Send failed", IrpSp);
                    569:             StDereferenceConnection ("Send failed", Connection);
                    570: 
                    571:             return;
                    572:         }
                    573: 
                    574:         ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    575: 
                    576:         //
                    577:         // It is probable that a frame arrived while we released
                    578:         // the connection's spin lock, so our state has probably changed.
                    579:         // When we cycle around this loop again, we will have the lock
                    580:         // again, so we can test the connection's send state.
                    581:         //
                    582: 
                    583:     } while (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
                    584: 
                    585:     //
                    586:     // Clear the PACKETIZE flag, indicating that we're no longer on the
                    587:     // PacketizeQueue or actively packetizing.  The flag was set by
                    588:     // StartPacketizingConnection to indicate that the connection was
                    589:     // already on the PacketizeQueue.
                    590:     //
                    591: 
                    592:     Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
                    593: 
                    594:     RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    595: 
                    596:     StDereferenceConnection ("PacketizeSend done", Connection);
                    597: 
                    598: } /* PacketizeSend */
                    599: 
                    600: 
                    601: VOID
                    602: CompleteSend(
                    603:     PTP_CONNECTION Connection
                    604:     )
                    605: 
                    606: /*++
                    607: 
                    608: Routine Description:
                    609: 
                    610:     This routine is called to complete a TDI send back to the
                    611:     caller. In the sample transport we assume that all sends
                    612:     complete successfully, but in other transports we would
                    613:     wait for a response from the remote.
                    614: 
                    615: Arguments:
                    616: 
                    617:     Connection - Pointer to a TP_CONNECTION object.
                    618: 
                    619: Return Value:
                    620: 
                    621:     none.
                    622: 
                    623: --*/
                    624: 
                    625: {
                    626:     KIRQL oldirql, cancelirql;
                    627:     PIRP Irp;
                    628:     PIO_STACK_LOCATION IrpSp;
                    629:     PLIST_ENTRY p;
                    630:     BOOLEAN EndOfRecord;
                    631: 
                    632:     //
                    633:     // Pick off TP_REQUEST objects from the connection's SendQueue until
                    634:     // we find one with an END_OF_RECORD mark embedded in it.
                    635:     //
                    636: 
                    637:     IoAcquireCancelSpinLock(&cancelirql);
                    638:     ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    639: 
                    640:     while (TRUE) {
                    641: 
                    642:         //
                    643:         // We know for a fact that we wouldn't be calling this routine if
                    644:         // we hadn't completed sending an entire message, since we
                    645:         // only set the ST_LAST bit in that case. Therefore, we
                    646:         // know that we will run into a request with the END_OF_RECORD
                    647:         // mark set BEFORE we will run out of requests on that queue,
                    648:         // so there is no reason to check to see if we ran off the end.
                    649:         // Note that it's possible that the send has been failed and the
                    650:         // connection not yet torn down; if this has happened, we could be
                    651:         // removing from an empty queue here. Make sure that doesn't happen.
                    652:         //
                    653: 
                    654:         if (Connection->SendQueue.Flink == &Connection->SendQueue) {
                    655: 
                    656:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    657:             IoReleaseCancelSpinLock(cancelirql);
                    658: 
                    659:             //
                    660:             // no requests to complete, things must have failed; just get out.
                    661:             //
                    662: 
                    663:             break;
                    664:         }
                    665: 
                    666:         p = RemoveHeadList (&Connection->SendQueue);
                    667: 
                    668:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    669:         Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
                    670:         IrpSp = IoGetCurrentIrpStackLocation (Irp);
                    671: 
                    672:         EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
                    673: 
                    674:         Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
                    675:         IoReleaseCancelSpinLock(cancelirql);
                    676: 
                    677:         //
                    678:         // Complete the send. Note that this may not actually call
                    679:         // IoCompleteRequest for the Irp until sometime later, if the
                    680:         // in-progress LLC resending going on below us needs to complete.
                    681:         //
                    682: 
                    683:         StCompleteSendIrp (
                    684:                 Irp,
                    685:                 STATUS_SUCCESS,
                    686:                 IRP_SEND_LENGTH(IrpSp));
                    687: 
                    688:         if (EndOfRecord) {
                    689:             break;
                    690:         }
                    691: 
                    692:         IoAcquireCancelSpinLock(&cancelirql);
                    693:         ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    694: 
                    695:     };
                    696: 
                    697:     //
                    698:     // Acquire the lock that we will return with.
                    699:     //
                    700: 
                    701:     ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    702: 
                    703:     //
                    704:     // We've finished processing the current send.  Update our state.
                    705:     //
                    706: 
                    707:     Connection->SendState = CONNECTION_SENDSTATE_IDLE;
                    708: 
                    709:     //
                    710:     // If there is another send pending on the connection, then initialize
                    711:     // it and start packetizing it.
                    712:     //
                    713: 
                    714:     if (!(IsListEmpty (&Connection->SendQueue))) {
                    715: 
                    716:         InitializeSend (Connection);
                    717: 
                    718:         //
                    719:         // This code is similar to calling StartPacketizingConnection
                    720:         // with the second parameter FALSE.
                    721:         //
                    722: 
                    723:         if ((!(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
                    724:             (!(Connection->Flags & CONNECTION_FLAGS_STOPPING))) {
                    725: 
                    726:             Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
                    727: 
                    728:             StReferenceConnection ("Packetize", Connection);
                    729: 
                    730:             ExInterlockedInsertTailList(
                    731:                 &Connection->Provider->PacketizeQueue,
                    732:                 &Connection->PacketizeLinkage,
                    733:                 &Connection->Provider->SpinLock);
                    734: 
                    735:         }
                    736: 
                    737:     }
                    738: 
                    739:     RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    740: 
                    741: } /* CompleteSend */
                    742: 
                    743: 
                    744: VOID
                    745: FailSend(
                    746:     IN PTP_CONNECTION Connection,
                    747:     IN NTSTATUS RequestStatus,
                    748:     IN BOOLEAN StopConnection
                    749:     )
                    750: 
                    751: /*++
                    752: 
                    753: Routine Description:
                    754: 
                    755:     This routine is called because something on the link caused this send to be
                    756:     unable to complete. There are a number of possible reasons for this to have
                    757:     happened, but all will fail with the common error STATUS_LINK_FAILED.
                    758:     or NO_RECEIVE response where the number of bytes specified exactly
                    759:     Here we retire all of the TdiSends on the connection's SendQueue up to
                    760:     and including the current one, which is the one that failed.
                    761: 
                    762:     Later - Actually, a send failing is cause for the entire circuit to wave
                    763:     goodbye to this life. We now simply tear down the connection completly.
                    764:     Any future sends on this connection will be blown away.
                    765: 
                    766: Arguments:
                    767: 
                    768:     Connection - Pointer to a TP_CONNECTION object.
                    769: 
                    770: Return Value:
                    771: 
                    772:     none.
                    773: 
                    774: --*/
                    775: 
                    776: {
                    777:     KIRQL oldirql, cancelirql;
                    778:     PIRP Irp;
                    779:     PIO_STACK_LOCATION IrpSp;
                    780:     PLIST_ENTRY p;
                    781:     BOOLEAN EndOfRecord;
                    782:     BOOLEAN GotCurrent = FALSE;
                    783: 
                    784: 
                    785:     //
                    786:     // Pick off IRP objects from the connection's SendQueue until
                    787:     // we get to this one. If this one does NOT have an EOF mark set, we'll
                    788:     // need to keep going until we hit one that does have EOF set. Note that
                    789:     // this may  cause us to continue failing sends that have not yet been
                    790:     // queued. (We do all this because ST does not provide stream mode sends.)
                    791:     //
                    792: 
                    793:     IoAcquireCancelSpinLock(&cancelirql);
                    794:     ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    795:     StReferenceConnection ("Failing Send", Connection);
                    796: 
                    797:     do {
                    798:         if (IsListEmpty (&Connection->SendQueue)) {
                    799: 
                    800:            //
                    801:            // got an empty list, so we've run out of send requests to fail
                    802:            // without running into an EOR. Set the connection flag that will
                    803:            // cause all further sends to be failed up to an EOR and get out
                    804:            // of here.
                    805:            //
                    806: 
                    807:            Connection->Flags |= CONNECTION_FLAGS_FAILING_TO_EOR;
                    808:            break;
                    809:         }
                    810:         p = RemoveHeadList (&Connection->SendQueue);
                    811:         Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
                    812:         IrpSp = IoGetCurrentIrpStackLocation (Irp);
                    813: 
                    814:         if (Irp == Connection->sp.CurrentSendIrp) {
                    815:            GotCurrent = TRUE;
                    816:         }
                    817:         EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
                    818: 
                    819:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    820:         Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
                    821:         IoReleaseCancelSpinLock(cancelirql);
                    822: 
                    823: 
                    824:         //
                    825:         // The following dereference will complete the I/O, provided removes
                    826:         // the last reference on the request object.  The I/O will complete
                    827:         // with the status and information stored in the Irp.  Therefore,
                    828:         // we set those values here before the dereference.
                    829:         //
                    830: 
                    831:         StCompleteSendIrp (Irp, RequestStatus, 0);
                    832:         IoAcquireCancelSpinLock(&cancelirql);
                    833:         ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    834:     } while (!EndOfRecord & !GotCurrent);
                    835: 
                    836:     //
                    837:     // We've finished processing the current send.  Update our state.
                    838:     //
                    839: 
                    840:     Connection->SendState = CONNECTION_SENDSTATE_IDLE;
                    841:     Connection->sp.CurrentSendIrp = NULL;
                    842: 
                    843:     RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    844:     IoReleaseCancelSpinLock(cancelirql);
                    845: 
                    846: 
                    847:     if (StopConnection) {
                    848:         StStopConnection (Connection, STATUS_LINK_FAILED);
                    849:     }
                    850: 
                    851:     StDereferenceConnection ("FailSend", Connection);
                    852: 
                    853: } /* FailSend */
                    854: 
                    855: 
                    856: VOID
                    857: InitializeSend(
                    858:     PTP_CONNECTION Connection
                    859:     )
                    860: 
                    861: /*++
                    862: 
                    863: Routine Description:
                    864: 
                    865:     This routine is called whenever the next send on a connection should
                    866:     be initialized; that is, all of the fields associated with the state
                    867:     of the current send are set to refer to the first send on the SendQueue.
                    868: 
                    869:     WARNING:  This routine is executed with the Connection lock acquired
                    870:     since it must be atomically executed with the caller's setup.
                    871: 
                    872: Arguments:
                    873: 
                    874:     Connection - Pointer to a TP_CONNECTION object.
                    875: 
                    876: Return Value:
                    877: 
                    878:     none.
                    879: 
                    880: --*/
                    881: 
                    882: {
                    883:     if (Connection->SendQueue.Flink != &Connection->SendQueue) {
                    884:         Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
                    885:         Connection->FirstSendIrp =
                    886:             CONTAINING_RECORD (Connection->SendQueue.Flink, IRP, Tail.Overlay.ListEntry);
                    887:         Connection->FirstSendMdl = Connection->FirstSendIrp->MdlAddress;
                    888:         Connection->FirstSendByteOffset = 0;
                    889:         Connection->sp.MessageBytesSent = 0;
                    890:         Connection->sp.CurrentSendIrp = Connection->FirstSendIrp;
                    891:         Connection->sp.CurrentSendMdl = Connection->FirstSendMdl;
                    892:         Connection->sp.SendByteOffset = Connection->FirstSendByteOffset;
                    893:         Connection->CurrentSendLength =
                    894:             IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
                    895: 
                    896:     }
                    897: } /* InitializeSend */
                    898: 
                    899: 
                    900: VOID
                    901: StCancelSend(
                    902:     IN PDEVICE_OBJECT DeviceObject,
                    903:     IN PIRP Irp
                    904:     )
                    905: 
                    906: /*++
                    907: 
                    908: Routine Description:
                    909: 
                    910:     This routine is called by the I/O system to cancel a send.
                    911:     The send is found on the connection's send queue; if it is the
                    912:     current request it is cancelled and the connection is torn down,
                    913:     otherwise it is silently cancelled.
                    914: 
                    915:     NOTE: This routine is called with the CancelSpinLock held and
                    916:     is responsible for releasing it.
                    917: 
                    918: Arguments:
                    919: 
                    920:     DeviceObject - Pointer to the device object for this driver.
                    921: 
                    922:     Irp - Pointer to the request packet representing the I/O request.
                    923: 
                    924: Return Value:
                    925: 
                    926:     none.
                    927: 
                    928: --*/
                    929: 
                    930: {
                    931:     KIRQL oldirql;
                    932:     PIO_STACK_LOCATION IrpSp;
                    933:     PTP_CONNECTION Connection;
                    934:     PIRP SendIrp;
                    935:     PLIST_ENTRY p;
                    936:     BOOLEAN Found;
                    937: 
                    938:     UNREFERENCED_PARAMETER (DeviceObject);
                    939: 
                    940:     //
                    941:     // Get a pointer to the current stack location in the IRP.  This is where
                    942:     // the function codes and parameters are stored.
                    943:     //
                    944: 
                    945:     IrpSp = IoGetCurrentIrpStackLocation (Irp);
                    946: 
                    947:     ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
                    948:             (IrpSp->MinorFunction == TDI_SEND));
                    949: 
                    950:     Connection = IrpSp->FileObject->FsContext;
                    951: 
                    952:     //
                    953:     // Since this IRP is still in the cancellable state, we know
                    954:     // that the connection is still around (although it may be in
                    955:     // the process of being torn down).
                    956:     //
                    957: 
                    958:     //
                    959:     // See if this is the IRP for the current send request.
                    960:     //
                    961: 
                    962:     ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                    963:     StReferenceConnection ("Cancelling Send", Connection);
                    964: 
                    965:     p = Connection->SendQueue.Flink;
                    966:     SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
                    967: 
                    968:     if (SendIrp == Irp) {
                    969: 
                    970:         //
                    971:         // yes, it is the first one on the send queue, so
                    972:         // trash the send/connection.
                    973:         //
                    974: 
                    975:         p = RemoveHeadList (&Connection->SendQueue);
                    976: 
                    977:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                    978:         IoReleaseCancelSpinLock (Irp->CancelIrql);
                    979: 
                    980: 
                    981:         //
                    982:         // The following dereference will complete the I/O, provided removes
                    983:         // the last reference on the request object.  The I/O will complete
                    984:         // with the status and information stored in the Irp.  Therefore,
                    985:         // we set those values here before the dereference.
                    986:         //
                    987: 
                    988:         StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
                    989: 
                    990:         //
                    991:         // Since we are cancelling the current send, blow away
                    992:         // the connection.
                    993:         //
                    994: 
                    995:         StStopConnection (Connection, STATUS_CANCELLED);
                    996: 
                    997:     } else {
                    998: 
                    999:         //
                   1000:         // Scan through the list, looking for this IRP.
                   1001:         //
                   1002: 
                   1003:         Found = FALSE;
                   1004:         p = p->Flink;
                   1005:         while (p != &Connection->SendQueue) {
                   1006: 
                   1007:             SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
                   1008:             if (SendIrp == Irp) {
                   1009: 
                   1010:                 //
                   1011:                 // Found it, remove it from the list here.
                   1012:                 //
                   1013: 
                   1014:                 RemoveEntryList (p);
                   1015: 
                   1016:                 Found = TRUE;
                   1017: 
                   1018:                 RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                   1019:                 IoReleaseCancelSpinLock (Irp->CancelIrql);
                   1020: 
                   1021:                 //
                   1022:                 // The following dereference will complete the I/O, provided removes
                   1023:                 // the last reference on the request object.  The I/O will complete
                   1024:                 // with the status and information stored in the Irp.  Therefore,
                   1025:                 // we set those values here before the dereference.
                   1026:                 //
                   1027: 
                   1028:                 StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
                   1029:                 break;
                   1030: 
                   1031:             }
                   1032: 
                   1033:             p = p->Flink;
                   1034: 
                   1035:         }
                   1036: 
                   1037:         if (!Found) {
                   1038: 
                   1039:             //
                   1040:             // We didn't find it!
                   1041:             //
                   1042: 
                   1043:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                   1044:             IoReleaseCancelSpinLock (Irp->CancelIrql);
                   1045:         }
                   1046: 
                   1047:     }
                   1048: 
                   1049:     StDereferenceConnection ("Cancelling Send", Connection);
                   1050: 
                   1051: }
                   1052: 
                   1053: 
                   1054: 
                   1055: VOID
                   1056: StSendCompletionHandler(
                   1057:     IN NDIS_HANDLE ProtocolBindingContext,
                   1058:     IN PNDIS_PACKET NdisPacket,
                   1059:     IN NDIS_STATUS NdisStatus
                   1060:     )
                   1061: 
                   1062: /*++
                   1063: 
                   1064: Routine Description:
                   1065: 
                   1066:     This routine is called by the I/O system to indicate that a connection-
                   1067:     oriented packet has been shipped and is no longer needed by the Physical
                   1068:     Provider.
                   1069: 
                   1070: Arguments:
                   1071: 
                   1072:     NdisContext - the value associated with the adapter binding at adapter
                   1073:                   open time (which adapter we're talking on).
                   1074: 
                   1075:     NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
                   1076: 
                   1077:     NdisStatus - the completion status of the send.
                   1078: 
                   1079: Return Value:
                   1080: 
                   1081:     none.
                   1082: 
                   1083: --*/
                   1084: 
                   1085: {
                   1086:     PSEND_PACKET_TAG SendContext;
                   1087:     PTP_PACKET Packet;
                   1088:     KIRQL oldirql, cancelirql;
                   1089:     PDEVICE_CONTEXT DeviceContext;
                   1090:     PTP_CONNECTION Connection;
                   1091:     PLIST_ENTRY p;
                   1092:     PIO_STACK_LOCATION IrpSp;
                   1093:     PTP_REQUEST request;
                   1094:     TA_NETBIOS_ADDRESS TempAddress;
                   1095:     ULONG returnLength;
                   1096:     NTSTATUS status;
                   1097:     PTDI_CONNECTION_INFORMATION remoteInformation;
                   1098: 
                   1099:     UNREFERENCED_PARAMETER(ProtocolBindingContext);
                   1100: 
                   1101:     SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0];
                   1102:     Packet = SendContext->Packet;
                   1103: 
                   1104:     DeviceContext = Packet->Provider;
                   1105: 
                   1106:     Packet->PacketSent = TRUE;
                   1107: 
                   1108:     switch (SendContext->Type) {
                   1109: 
                   1110:     case TYPE_I_FRAME:
                   1111: 
                   1112:         //
                   1113:         // Dereference the IRP that this packet was sent for.
                   1114:         //
                   1115: 
                   1116:         IrpSp = (PIO_STACK_LOCATION)(SendContext->Owner);
                   1117: 
                   1118:         if (Packet->CompleteSend) {
                   1119:             CompleteSend(IRP_CONNECTION(IrpSp));
                   1120:         }
                   1121:         StDereferenceSendIrp("Destroy packet", IrpSp);
                   1122:         break;
                   1123: 
                   1124:     case TYPE_D_FRAME:
                   1125: 
                   1126:         //
                   1127:         // Finish tearing down the connection.
                   1128:         //
                   1129: 
                   1130:         StDereferenceConnection("Disconnect completed", (PTP_CONNECTION)(SendContext->Owner));
                   1131:         break;
                   1132: 
                   1133:     case TYPE_G_FRAME:
                   1134: 
                   1135:         //
                   1136:         // Addresses get their own frames; let the address know it's ok to
                   1137:         // use the frame again, and exit to avoid normal packet completion.
                   1138:         //
                   1139: 
                   1140:         StSendDatagramCompletion ((PTP_ADDRESS)(SendContext->Owner),
                   1141:             NdisPacket,
                   1142:             NdisStatus);
                   1143:         return;
                   1144: 
                   1145:     case TYPE_C_FRAME:
                   1146: 
                   1147:         //
                   1148:         // Complete the TdiConnect request; note that he better
                   1149:         // have accepted it quickly since we will immediately
                   1150:         // start sending data if required.
                   1151:         //
                   1152: 
                   1153:         Connection = (PTP_CONNECTION)(SendContext->Owner);
                   1154: 
                   1155:         IoAcquireCancelSpinLock (&cancelirql);
                   1156:         ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
                   1157: 
                   1158:         p = RemoveHeadList (&Connection->InProgressRequest);
                   1159: 
                   1160:         //
                   1161:         // Turn off the connection request timer if there is one, and set
                   1162:         // this connection's state to READY.
                   1163:         //
                   1164: 
                   1165:         Connection->Flags |= CONNECTION_FLAGS_READY;
                   1166: 
                   1167:         INCREMENT_COUNTER (Connection->Provider, OpenConnections);
                   1168: 
                   1169:         //
                   1170:         // Record that the connect request has been successfully
                   1171:         // completed by TpCompleteRequest.
                   1172:         //
                   1173: 
                   1174:         Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
                   1175: 
                   1176:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
                   1177: 
                   1178:         //
                   1179:         // Now complete the request and get out.
                   1180:         //
                   1181: 
                   1182:         if (p == &Connection->InProgressRequest) {
                   1183:             Connection->IndicationInProgress = FALSE;
                   1184:             PANIC ("ProcessSessionConfirm: TdiConnect evaporated!\n");
                   1185:             IoReleaseCancelSpinLock (cancelirql);
                   1186:             break;
                   1187:         }
                   1188: 
                   1189:         //
                   1190:         // We have a completed connection with a queued connect. Complete
                   1191:         // the connect.
                   1192:         //
                   1193: 
                   1194:         request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
                   1195:         request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
                   1196:         IoReleaseCancelSpinLock(cancelirql);
                   1197: 
                   1198:         IrpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
                   1199:         remoteInformation =
                   1200:            ((PTDI_REQUEST_KERNEL)(&IrpSp->Parameters))->ReturnConnectionInformation;
                   1201:         if (remoteInformation != NULL) {
                   1202:             try {
                   1203:                 if (remoteInformation->RemoteAddressLength != 0) {
                   1204: 
                   1205:                     //
                   1206:                     // Build a temporary TA_NETBIOS_ADDRESS, then
                   1207:                     // copy over as many bytes as fit.
                   1208:                     //
                   1209: 
                   1210:                     TdiBuildNetbiosAddress(
                   1211:                         Connection->CalledAddress.NetbiosName,
                   1212:                         (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
                   1213:                             TDI_ADDRESS_NETBIOS_TYPE_GROUP),
                   1214:                         &TempAddress);
                   1215: 
                   1216:                     if (remoteInformation->RemoteAddressLength >=
                   1217:                                            sizeof (TA_NETBIOS_ADDRESS)) {
                   1218: 
                   1219:                         returnLength = sizeof(TA_NETBIOS_ADDRESS);
                   1220:                         remoteInformation->RemoteAddressLength = returnLength;
                   1221: 
                   1222:                     } else {
                   1223: 
                   1224:                         returnLength = remoteInformation->RemoteAddressLength;
                   1225: 
                   1226:                     }
                   1227: 
                   1228:                     RtlCopyMemory(
                   1229:                         (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
                   1230:                         &TempAddress,
                   1231:                         returnLength);
                   1232: 
                   1233:                 } else {
                   1234: 
                   1235:                     returnLength = 0;
                   1236:                 }
                   1237: 
                   1238:                 status = STATUS_SUCCESS;
                   1239: 
                   1240:             } except (EXCEPTION_EXECUTE_HANDLER) {
                   1241: 
                   1242:                 returnLength = 0;
                   1243:                 status = GetExceptionCode ();
                   1244: 
                   1245:             }
                   1246: 
                   1247:         } else {
                   1248: 
                   1249:             status = STATUS_SUCCESS;
                   1250:             returnLength = 0;
                   1251: 
                   1252:         }
                   1253: 
                   1254:         RtlCopyMemory( Connection->RemoteName, Connection->CalledAddress.NetbiosName, 16 );
                   1255:         Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
                   1256: 
                   1257:         //
                   1258:         // Reference the connection so it stays around after
                   1259:         // the request is completed.
                   1260:         //
                   1261: 
                   1262:         StReferenceConnection("Connect completed", Connection);
                   1263: 
                   1264:         StCompleteRequest (request, status, returnLength);
                   1265: 
                   1266:         break;
                   1267: 
                   1268:     }
                   1269: 
                   1270:     StDestroyPacket(Packet);
                   1271: 
                   1272: } /* StSendCompletionHandler */
                   1273: 
                   1274: 
                   1275: VOID
                   1276: StNdisSend(
                   1277:     IN PTP_PACKET Packet
                   1278:     )
                   1279: 
                   1280: /*++
                   1281: 
                   1282: Routine Description:
                   1283: 
                   1284:     This routine sends an NDIS packet
                   1285:     This routine is used to ensure that receive sequence numbers on
                   1286:     packets are numbered correctly. It is called in place of NdisSend
                   1287:     and after assigning the receive sequence number it locks out other
                   1288:     sends until the NdisSend call has returned (not necessarily completed),
                   1289:     insuring that the packets with increasing receive sequence numbers
                   1290:     are queue in the right order by the MAC.
                   1291: 
                   1292:     NOTE: This routine is called with the link spinlock held,
                   1293:     and it returns with it released.
                   1294: 
                   1295: Arguments:
                   1296: 
                   1297:     Packet - Pointer to a TP_PACKET object.
                   1298: 
                   1299: Return Value:
                   1300: 
                   1301:     None.
                   1302: 
                   1303: --*/
                   1304: 
                   1305: {
                   1306: 
                   1307:     NDIS_STATUS NdisStatus;
                   1308: 
                   1309:     NdisSend (
                   1310:         &NdisStatus,
                   1311:         ((PDEVICE_CONTEXT)(Packet->Provider))->NdisBindingHandle,
                   1312:         Packet->NdisPacket);
                   1313: 
                   1314:     if (NdisStatus != NDIS_STATUS_PENDING) {
                   1315: 
                   1316:         StSendCompletionHandler(
                   1317:             Packet->Provider,
                   1318:             Packet->NdisPacket,
                   1319:             NdisStatus);
                   1320:     }
                   1321: 
                   1322: }   /* StNdisSend */
                   1323: 
                   1324: 
                   1325: 
                   1326: NTSTATUS
                   1327: BuildBufferChainFromMdlChain (
                   1328:     IN NDIS_HANDLE BufferPoolHandle,
                   1329:     IN PMDL CurrentMdl,
                   1330:     IN ULONG ByteOffset,
                   1331:     IN ULONG DesiredLength,
                   1332:     OUT PNDIS_BUFFER *Destination,
                   1333:     OUT PMDL *NewCurrentMdl,
                   1334:     OUT ULONG *NewByteOffset,
                   1335:     OUT ULONG *TrueLength
                   1336:     )
                   1337: 
                   1338: /*++
                   1339: 
                   1340: Routine Description:
                   1341: 
                   1342:     This routine is called to build an NDIS_BUFFER chain from a source Mdl chain and
                   1343:     offset into it. We assume we don't know the length of the source Mdl chain,
                   1344:     and we must allocate the NDIS_BUFFERs for the destination chain, which
                   1345:     we do from the NDIS buffer pool.
                   1346: 
                   1347:     The NDIS_BUFFERs that are returned are mapped and locked. (Actually, the pages in
                   1348:     them are in the same state as those in the source MDLs.)
                   1349: 
                   1350:     If the system runs out of memory while we are building the destination
                   1351:     NDIS_BUFFER chain, we completely clean up the built chain and return with
                   1352:     NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
                   1353:     and ByteOffset. TrueLength is set to 0.
                   1354: 
                   1355: Environment:
                   1356: 
                   1357:     Kernel Mode, Source Mdls locked. It is recommended, although not required,
                   1358:     that the source Mdls be mapped and locked prior to calling this routine.
                   1359: 
                   1360: Arguments:
                   1361: 
                   1362:     BufferPoolHandle - The buffer pool to allocate buffers from.
                   1363: 
                   1364:     CurrentMdl - Points to the start of the Mdl chain from which to draw the
                   1365:     packet.
                   1366: 
                   1367:     ByteOffset - Offset within this MDL to start the packet at.
                   1368: 
                   1369:     DesiredLength - The number of bytes to insert into the packet.
                   1370: 
                   1371:     Destination - returned pointer to the NDIS_BUFFER chain describing the packet.
                   1372: 
                   1373:     NewCurrentMdl - returned pointer to the Mdl that would be used for the next
                   1374:         byte of packet. NULL if the source Mdl chain was exhausted.
                   1375: 
                   1376:     NewByteOffset - returned offset into the NewCurrentMdl for the next byte of
                   1377:         packet. NULL if the source Mdl chain was exhausted.
                   1378: 
                   1379:     TrueLength - The actual length of the returned NDIS_BUFFER Chain. If less than
                   1380:         DesiredLength, the source Mdl chain was exhausted.
                   1381: 
                   1382: Return Value:
                   1383: 
                   1384:     STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded (even if
                   1385:     shorter than the desired chain).
                   1386: 
                   1387:     STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while building the
                   1388:     destination chain.
                   1389: 
                   1390: --*/
                   1391: {
                   1392:     ULONG AvailableBytes;
                   1393:     PMDL OldMdl;
                   1394:     PNDIS_BUFFER NewNdisBuffer;
                   1395:     NDIS_STATUS NdisStatus;
                   1396: 
                   1397: 
                   1398:     AvailableBytes = MmGetMdlByteCount (CurrentMdl) - ByteOffset;
                   1399:     if (AvailableBytes > DesiredLength) {
                   1400:         AvailableBytes = DesiredLength;
                   1401:     }
                   1402: 
                   1403:     OldMdl = CurrentMdl;
                   1404:     *NewCurrentMdl = OldMdl;
                   1405:     *NewByteOffset = ByteOffset + AvailableBytes;
                   1406:     *TrueLength = AvailableBytes;
                   1407: 
                   1408: 
                   1409:     //
                   1410:     // Build the first NDIS_BUFFER, which could conceivably be the only one...
                   1411:     //
                   1412: 
                   1413:     NdisCopyBuffer(
                   1414:         &NdisStatus,
                   1415:         &NewNdisBuffer,
                   1416:         BufferPoolHandle,
                   1417:         OldMdl,
                   1418:         ByteOffset,
                   1419:         AvailableBytes);
                   1420: 
                   1421: 
                   1422:     if (NdisStatus != NDIS_STATUS_SUCCESS) {
                   1423:         *NewByteOffset = ByteOffset;
                   1424:         *TrueLength = 0;
                   1425:         *Destination = NULL;
                   1426:         return STATUS_INSUFFICIENT_RESOURCES;
                   1427:     }
                   1428: 
                   1429:     *Destination = NewNdisBuffer;
                   1430: 
                   1431:     //
                   1432:     // Was the first NDIS_BUFFER enough data, or are we out of Mdls?
                   1433:     //
                   1434: 
                   1435:     if ((AvailableBytes == DesiredLength) || (OldMdl->Next == NULL)) {
                   1436:         if (*NewByteOffset >= MmGetMdlByteCount (OldMdl)) {
                   1437:             *NewCurrentMdl = OldMdl->Next;
                   1438:             *NewByteOffset = 0;
                   1439:         }
                   1440:         return STATUS_SUCCESS;
                   1441:     }
                   1442: 
                   1443:     //
                   1444:     // Need more data, so follow the in Mdl chain to create a packet.
                   1445:     //
                   1446: 
                   1447:     OldMdl = OldMdl->Next;
                   1448:     *NewCurrentMdl = OldMdl;
                   1449: 
                   1450:     while (OldMdl != NULL) {
                   1451:         AvailableBytes = DesiredLength - *TrueLength;
                   1452:         if (AvailableBytes > MmGetMdlByteCount (OldMdl)) {
                   1453:             AvailableBytes = MmGetMdlByteCount (OldMdl);
                   1454:         }
                   1455: 
                   1456:         NdisCopyBuffer(
                   1457:             &NdisStatus,
                   1458:             &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
                   1459:             BufferPoolHandle,
                   1460:             OldMdl,
                   1461:             0,
                   1462:             AvailableBytes);
                   1463: 
                   1464:         if (NdisStatus != NDIS_STATUS_SUCCESS) {
                   1465: 
                   1466:             //
                   1467:             // ran out of resources. put back what we've used in this call and
                   1468:             // return the error.
                   1469:             //
                   1470: 
                   1471:             while (*Destination != NULL) {
                   1472:                 NewNdisBuffer = NDIS_BUFFER_LINKAGE(*Destination);
                   1473:                 NdisFreeBuffer (*Destination);
                   1474:                 *Destination = NewNdisBuffer;
                   1475:             }
                   1476: 
                   1477:             *NewByteOffset = ByteOffset;
                   1478:             *TrueLength = 0;
                   1479:             *NewCurrentMdl = CurrentMdl;
                   1480: 
                   1481:             return STATUS_INSUFFICIENT_RESOURCES;
                   1482:         }
                   1483: 
                   1484:         NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
                   1485: 
                   1486:         *TrueLength += AvailableBytes;
                   1487:         *NewByteOffset = AvailableBytes;
                   1488: 
                   1489:         if (*TrueLength == DesiredLength) {
                   1490:             if (*NewByteOffset == MmGetMdlByteCount (OldMdl)) {
                   1491:                 *NewCurrentMdl = OldMdl->Next;
                   1492:                 *NewByteOffset = 0;
                   1493:             }
                   1494:             return STATUS_SUCCESS;
                   1495:         }
                   1496:         OldMdl = OldMdl->Next;
                   1497:         *NewCurrentMdl = OldMdl;
                   1498: 
                   1499:     } // while (mdl chain exists)
                   1500: 
                   1501:     *NewCurrentMdl = NULL;
                   1502:     *NewByteOffset = 0;
                   1503:     return STATUS_SUCCESS;
                   1504: 
                   1505: } // BuildBufferChainFromMdlChain
                   1506: 

unix.superglobalmegacorp.com

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