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

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1989-1993  Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     iframes.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains routines called to handle i-frames received
        !            12:     from the NDIS driver. Most of these routines are called at receive
        !            13:     indication time.
        !            14: 
        !            15: Environment:
        !            16: 
        !            17:     Kernel mode, DISPATCH_LEVEL.
        !            18: 
        !            19: Revision History:
        !            20: 
        !            21: --*/
        !            22: 
        !            23: #include "st.h"
        !            24: #if 27
        !            25: ULONG StNoisyReceives = 0;
        !            26: ULONG StRcvLoc = 0;
        !            27: ULONG StRcvs[10];
        !            28: #endif
        !            29: 
        !            30: 
        !            31: 
        !            32: NTSTATUS
        !            33: StProcessIIndicate(
        !            34:     IN PTP_CONNECTION Connection,
        !            35:     IN PST_HEADER StHeader,
        !            36:     IN UINT StIndicatedLength,
        !            37:     IN UINT StTotalLength,
        !            38:     IN NDIS_HANDLE ReceiveContext,
        !            39:     IN BOOLEAN Last
        !            40:     )
        !            41: 
        !            42: /*++
        !            43: 
        !            44: Routine Description:
        !            45: 
        !            46:     This routine processes a received I frame at indication time. It will do
        !            47:     all necessary verification processing of the frame and pass those frames
        !            48:     that are valid on to the proper handling routines.
        !            49: 
        !            50: Arguments:
        !            51: 
        !            52:     Connection - The connection that the data is destined for.
        !            53: 
        !            54:     StHeader - A pointer to the start of the ST header in the packet.
        !            55: 
        !            56:     StIndicatedLength - The length of the packet indicated, starting at
        !            57:         StHeader.
        !            58: 
        !            59:     StTotalLength - The total length of the packet, starting at StHeader.
        !            60: 
        !            61:     ReceiveContext - A magic value for NDIS that indicates which packet we're
        !            62:         talking about, used for calling TransferData
        !            63: 
        !            64:     Last - TRUE if this is the last packet in a send.
        !            65: 
        !            66: Return Value:
        !            67: 
        !            68:     STATUS_SUCCESS if we've consumed the packet, but
        !            69:     STATUS_MORE_PROCESSING_REQUIRED if we did so and also
        !            70:     activated a receive; this tells the caller not to
        !            71:     remove the connection refcount.
        !            72: 
        !            73: --*/
        !            74: 
        !            75: {
        !            76:     KIRQL oldirql;
        !            77:     NTSTATUS status, tmpstatus;
        !            78:     KIRQL cancelirql;
        !            79:     PDEVICE_CONTEXT deviceContext;
        !            80:     NDIS_STATUS ndisStatus;
        !            81:     PNDIS_PACKET ndisPacket;
        !            82:     PSINGLE_LIST_ENTRY linkage;
        !            83:     PIRP irp;
        !            84:     PIO_STACK_LOCATION irpSp;
        !            85:     PNDIS_BUFFER ndisBuffer;
        !            86:     ULONG destBytes;
        !            87:     ULONG bufferChainLength;
        !            88:     ULONG indicateBytesTransferred;
        !            89:     ULONG ndisBytesTransferred;
        !            90:     PUCHAR DataHeader;
        !            91:     ULONG DataTotalLength;
        !            92:     ULONG DataIndicatedLength;
        !            93:     UINT BytesToTransfer;
        !            94:     ULONG bytesIndicated;
        !            95:     PRECEIVE_PACKET_TAG receiveTag;
        !            96:     PTP_ADDRESS address;
        !            97:     PTP_ADDRESS_FILE addressFile;
        !            98:     PMDL SavedCurrentMdl;
        !            99:     ULONG SavedCurrentByteOffset;
        !           100:     LARGE_INTEGER time;
        !           101:     ULONG DumpData[2];
        !           102:     BOOLEAN CancelSpinLockHeld = FALSE;
        !           103: #if 27
        !           104:     if (StNoisyReceives) {
        !           105:         DbgPrint ("Indicate %d, Total %d\n", StIndicatedLength, StTotalLength);
        !           106:     }
        !           107:     if (StTotalLength > 1000) {
        !           108:         StRcvs[StRcvLoc] = StTotalLength;
        !           109:         StRcvLoc = (StRcvLoc + 1) % 10;
        !           110:     }
        !           111: #endif
        !           112: 
        !           113: 
        !           114:     //
        !           115:     // copy this packet into our receive buffer.
        !           116:     //
        !           117: 
        !           118:     deviceContext = Connection->Provider;
        !           119:     addressFile = Connection->AddressFile;
        !           120:     address = addressFile->Address;
        !           121: 
        !           122:     ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
        !           123: 
        !           124:     //
        !           125:     // If we have a previous receive that is pending
        !           126:     // completion, then we need to ignore this frame.
        !           127:     // This may be common on MP.
        !           128:     //
        !           129: 
        !           130:     if (Connection->Flags2 & CONNECTION_FLAGS2_RC_PENDING) {
        !           131: 
        !           132:         Connection->IndicationInProgress = FALSE;
        !           133:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
        !           134: 
        !           135:         return STATUS_SUCCESS;
        !           136:     }
        !           137: 
        !           138:     DataHeader = (PUCHAR)StHeader + sizeof(ST_HEADER);
        !           139:     DataTotalLength = StTotalLength - sizeof(ST_HEADER);
        !           140:     DataIndicatedLength = StIndicatedLength - sizeof(ST_HEADER);
        !           141: 
        !           142:     //
        !           143:     // Initialize this to zero, in case we do not indicate or
        !           144:     // the client does not fill it in.
        !           145:     //
        !           146: 
        !           147:     indicateBytesTransferred = 0;
        !           148: 
        !           149:     if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
        !           150: 
        !           151:         //
        !           152:         // check first to see if there is a receive available. If there is,
        !           153:         // use it before doing an indication.
        !           154:         //
        !           155: 
        !           156:         if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
        !           157: 
        !           158:             //
        !           159:             // Found a receive, so make it the active one and
        !           160:             // cycle around again.
        !           161:             //
        !           162: 
        !           163:             Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
        !           164:             Connection->MessageBytesReceived = 0;
        !           165:             Connection->MessageBytesAcked = 0;
        !           166:             Connection->CurrentReceiveRequest =
        !           167:                 CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
        !           168:                                    TP_REQUEST, Linkage);
        !           169:             Connection->CurrentReceiveMdl =
        !           170:                 Connection->CurrentReceiveRequest->Buffer2;
        !           171:             Connection->ReceiveLength =
        !           172:                 Connection->CurrentReceiveRequest->Buffer2Length;
        !           173:             Connection->ReceiveByteOffset = 0;
        !           174:             status = STATUS_SUCCESS;
        !           175:             goto NormalReceive;
        !           176:         }
        !           177: 
        !           178:         //
        !           179:         // A receive is not active.  Post a receive event.
        !           180:         //
        !           181: 
        !           182:         if (!addressFile->RegisteredReceiveHandler) {
        !           183: 
        !           184:             //
        !           185:             // There is no receive posted to the Connection, and
        !           186:             // no event handler. Set the RECEIVE_WAKEUP bit, so that when a
        !           187:             // receive does become available, it will restart the
        !           188:             // current send. Also send a NoReceive to tell the other
        !           189:             // guy he needs to resynch.
        !           190:             //
        !           191: 
        !           192:             Connection->IndicationInProgress = FALSE;
        !           193:             return STATUS_SUCCESS;
        !           194:         }
        !           195: 
        !           196:         if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
        !           197:             Connection->IndicationInProgress = FALSE;
        !           198:             RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
        !           199: 
        !           200:             return STATUS_SUCCESS;
        !           201:         }
        !           202: 
        !           203:         RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
        !           204: 
        !           205:         //
        !           206:         // Indicate to the user. For BytesAvailable we
        !           207:         // always use DataTotalLength; for BytesIndicated we use
        !           208:         // MIN (DataIndicatedLength, DataTotalLength).
        !           209:         //
        !           210:         // To clarify BytesIndicated, on an Ethernet packet
        !           211:         // which is padded DataTotalLength will be shorter; on an
        !           212:         // Ethernet packet which is not padded and which is
        !           213:         // completely indicated, the two will be equal; and
        !           214:         // on a long Ethernet packet DataIndicatedLength
        !           215:         // will be shorter.
        !           216:         //
        !           217: 
        !           218:         bytesIndicated = DataIndicatedLength;
        !           219:         if (DataTotalLength < bytesIndicated) {
        !           220:             bytesIndicated = DataTotalLength;
        !           221:         }
        !           222: 
        !           223:         status = (*addressFile->ReceiveHandler)(
        !           224:                     addressFile->ReceiveHandlerContext,
        !           225:                     Connection->Context,
        !           226:                     deviceContext->MacInfo.CopyLookahead ?
        !           227:                         TDI_RECEIVE_COPY_LOOKAHEAD : 0,    // ReceiveFlags
        !           228:                     bytesIndicated,
        !           229:                     DataTotalLength,             // BytesAvailable
        !           230:                     &indicateBytesTransferred,
        !           231:                     DataHeader,
        !           232:                     &irp);
        !           233: 
        !           234:         if (status == STATUS_SUCCESS) {
        !           235: 
        !           236:             //
        !           237:             // The client has accepted some or all of the indicated data in
        !           238:             // the event handler.  Update MessageBytesReceived variable in
        !           239:             // the Connection.
        !           240:             //
        !           241: 
        !           242:             Connection->MessageBytesReceived += indicateBytesTransferred;
        !           243:             Connection->IndicationInProgress = FALSE;
        !           244: 
        !           245:             return STATUS_SUCCESS;
        !           246: 
        !           247:         } else if (status == STATUS_DATA_NOT_ACCEPTED) {
        !           248: 
        !           249:             //
        !           250:             // Either there is no event handler installed (the default
        !           251:             // handler returns this code) or the event handler is not
        !           252:             // able to process the received data at this time.  If there
        !           253:             // is a TdiReceive request outstanding on this Connection's
        !           254:             // ReceiveQueue, then we may use it to receive this data.
        !           255:             // If there is no request outstanding, then we must initiate
        !           256:             // flow control at the transport level.
        !           257:             //
        !           258: 
        !           259:             ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
        !           260:             if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
        !           261: 
        !           262:                 //
        !           263:                 // There is no receive posted to the Connection, and
        !           264:                 // the event handler didn't want to accept the incoming
        !           265:                 // data.
        !           266:                 //
        !           267: 
        !           268:                 Connection->IndicationInProgress = FALSE;
        !           269:                 return STATUS_SUCCESS;
        !           270: 
        !           271:             } else {
        !           272: 
        !           273:                 //
        !           274:                 // Found a receive, so make it the active one. This will cause
        !           275:                 // an NdisTransferData below, so we don't dereference the
        !           276:                 // Connection here.
        !           277:                 //
        !           278: 
        !           279:                 Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
        !           280:                 Connection->MessageBytesReceived = 0;
        !           281:                 Connection->MessageBytesAcked = 0;
        !           282:                 Connection->CurrentReceiveRequest =
        !           283:                     CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
        !           284:                                        TP_REQUEST, Linkage);
        !           285:                 Connection->CurrentReceiveMdl =
        !           286:                     Connection->CurrentReceiveRequest->Buffer2;
        !           287:                 Connection->ReceiveLength =
        !           288:                     Connection->CurrentReceiveRequest->Buffer2Length;
        !           289:                 Connection->ReceiveByteOffset = 0;
        !           290:             }
        !           291: 
        !           292:         } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {
        !           293: 
        !           294:             PTP_REQUEST SpecialIrpRequest;
        !           295:             ULONG SpecialIrpLength;
        !           296: 
        !           297:             //
        !           298:             // The client's event handler has returned an IRP in the
        !           299:             // form of a TdiReceive that is to be associated with this
        !           300:             // data.  The request will be installed at the front of the
        !           301:             // ReceiveQueue, and then made the active receive request.
        !           302:             // This request will be used to accept the incoming data, which
        !           303:             // will happen below.
        !           304:             //
        !           305: 
        !           306:             //
        !           307:             // Queueing a receive of any kind causes a Connection reference;
        !           308:             // that's what we've just done here, so make the Connection stick
        !           309:             // around. We create a request to keep a packets outstanding ref
        !           310:             // count for the current IRP; we queue this on the connection's
        !           311:             // receive queue so we can treat it like a normal receive. If
        !           312:             // we can't get a request to describe this irp, we can't keep it
        !           313:             // around hoping for better later; we simple fail it with
        !           314:             // insufficient resources. Note this is only likely to happen if
        !           315:             // we've completely run out of transport memory.
        !           316:             //
        !           317: 
        !           318:             irp->IoStatus.Information = 0;  // byte transfer count.
        !           319:             irp->IoStatus.Status = STATUS_PENDING;
        !           320:             irpSp = IoGetCurrentIrpStackLocation (irp);
        !           321: 
        !           322:             ASSERT (irpSp->FileObject->FsContext == Connection);
        !           323: 
        !           324:             SpecialIrpLength =
        !           325:                 ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveLength;
        !           326: 
        !           327:             //
        !           328:             // The normal path, for longer receives.
        !           329:             //
        !           330: 
        !           331:             time.HighPart = 0;
        !           332:             time.LowPart = 0;
        !           333: 
        !           334:             status = StCreateRequest (
        !           335:                         irp,
        !           336:                         Connection,
        !           337:                         REQUEST_FLAGS_CONNECTION | REQUEST_FLAGS_SEND_RCV,
        !           338:                         irp->MdlAddress,
        !           339:                         ((PTDI_REQUEST_KERNEL_RECEIVE )&irpSp->Parameters)->ReceiveLength,
        !           340:                         time,
        !           341:                         &SpecialIrpRequest);
        !           342: 
        !           343:             if (!NT_SUCCESS (status)) {
        !           344:                 ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
        !           345:                 Connection->ReceiveByteOffset = 0;
        !           346:                 Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
        !           347:                 RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
        !           348: 
        !           349:                 Connection->IndicationInProgress = FALSE;
        !           350: 
        !           351:                 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
        !           352: 
        !           353:                 IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
        !           354:                 return STATUS_INSUFFICIENT_RESOURCES;
        !           355:             }
        !           356: 
        !           357:             //
        !           358:             // If the Connection is stopping, abort this request.
        !           359:             //
        !           360: 
        !           361:             IoAcquireCancelSpinLock(&cancelirql);
        !           362:             ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
        !           363: 
        !           364:             if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
        !           365:                 Connection->IndicationInProgress = FALSE;
        !           366:                 RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
        !           367: 
        !           368:                 IoReleaseCancelSpinLock(cancelirql);
        !           369:                 StCompleteRequest (
        !           370:                     SpecialIrpRequest,
        !           371:                     Connection->Status,
        !           372:                     0);
        !           373:                 return STATUS_SUCCESS;    // we have consumed the packet
        !           374: 
        !           375:             }
        !           376: 
        !           377:             //
        !           378:             // Insert the request on the head of the connection's
        !           379:             // receive queue, so it can be handled like a normal
        !           380:             // receive.
        !           381:             //
        !           382: 
        !           383:             InsertHeadList (&Connection->ReceiveQueue, &SpecialIrpRequest->Linkage);
        !           384: 
        !           385:             Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
        !           386:             Connection->ReceiveLength = ((PTDI_REQUEST_KERNEL_RECEIVE )&irpSp->Parameters)->ReceiveLength;
        !           387:             Connection->MessageBytesReceived = indicateBytesTransferred;
        !           388:             Connection->MessageBytesAcked = 0;
        !           389:             Connection->CurrentReceiveRequest = SpecialIrpRequest;
        !           390:             Connection->CurrentReceiveMdl = irp->MdlAddress;
        !           391:             Connection->ReceiveByteOffset = 0;
        !           392:             Connection->CurrentReceiveRequest->Owner = ConnectionType;
        !           393: 
        !           394:             //
        !           395:             // If this IRP has been cancelled, then call the
        !           396:             // cancel routine.
        !           397:             //
        !           398: 
        !           399:             if (irp->Cancel) {
        !           400: 
        !           401:                 Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
        !           402:                 Connection->IndicationInProgress = FALSE;
        !           403:                 RELEASE_SPIN_LOCK (&Connection->SpinLock,oldirql);
        !           404:                 irp->CancelIrql = cancelirql;
        !           405:                 StCancelReceive((PDEVICE_OBJECT)deviceContext, irp);
        !           406: 
        !           407:                 return STATUS_SUCCESS;
        !           408: 
        !           409:             } else {
        !           410: 
        !           411:                 irp->CancelRoutine = StCancelReceive;
        !           412: 
        !           413:                 status = STATUS_MORE_PROCESSING_REQUIRED;
        !           414: 
        !           415:                 //
        !           416:                 // Make a note so we know to release the cancel
        !           417:                 // spinlock below.
        !           418:                 //
        !           419: 
        !           420:                 CancelSpinLockHeld = TRUE;
        !           421: 
        !           422:             }
        !           423: 
        !           424:         } else {
        !           425: 
        !           426:             //
        !           427:             // An unknown return code has been returned by the
        !           428:             // client's event handler.  This is a client programming
        !           429:             // error.  Because this can only occur when kernel-mode
        !           430:             // clients have been coded incorrectly, we should beat
        !           431:             // him with a stick.  We have to do SOMETHING, or this
        !           432:             // Connection will HANG.
        !           433:             //
        !           434: 
        !           435:             Connection->IndicationInProgress = FALSE;
        !           436:             return STATUS_SUCCESS;
        !           437: 
        !           438:         }
        !           439: 
        !           440:     } else {
        !           441: 
        !           442:         //
        !           443:         // A receive is active, set the status to show
        !           444:         // that so far.
        !           445:         //
        !           446: 
        !           447:         status = STATUS_SUCCESS;
        !           448: 
        !           449:     }
        !           450: 
        !           451: 
        !           452: NormalReceive:;
        !           453: 
        !           454:     //
        !           455:     // NOTE: The connection spinlock is held here.
        !           456:     //
        !           457:     // We should only get through here if a receive is active
        !           458:     // and we have not released the lock since checking or
        !           459:     // making one active.
        !           460:     //
        !           461: 
        !           462:     ASSERT(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE);
        !           463: 
        !           464:     //
        !           465:     // The status should be SUCCESS (we found an active receive)
        !           466:     // or MORE_PROCESSING_REQUIRED (we made a new receive active).
        !           467:     //
        !           468: 
        !           469:     ASSERT ((status == STATUS_SUCCESS) || (status == STATUS_MORE_PROCESSING_REQUIRED));
        !           470: 
        !           471:     destBytes = Connection->ReceiveLength - Connection->MessageBytesReceived;
        !           472:     StReferenceRequest ("Transfer Data", Connection->CurrentReceiveRequest);
        !           473: 
        !           474:     RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
        !           475:     if (CancelSpinLockHeld) {
        !           476:         IoReleaseCancelSpinLock (cancelirql);
        !           477:     }
        !           478: 
        !           479:     //
        !           480:     // get a packet for the coming transfer
        !           481:     //
        !           482: 
        !           483:     linkage = ExInterlockedPopEntryList(
        !           484:         &deviceContext->ReceivePacketPool,
        !           485:         &deviceContext->Interlock);
        !           486: 
        !           487:     if (linkage != NULL) {
        !           488:         ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
        !           489:     } else {
        !           490:         (VOID)ExInterlockedIncrementLong(
        !           491:             (PLONG)&deviceContext->ReceivePacketExhausted,
        !           492:             &deviceContext->Interlock);
        !           493:         StDereferenceRequest ("No receive packet", Connection->CurrentReceiveRequest);
        !           494: 
        !           495:         // We could not get a receive packet.
        !           496:         //
        !           497: 
        !           498:         Connection->IndicationInProgress = FALSE;
        !           499:         return status;
        !           500:     }
        !           501: 
        !           502:     //
        !           503:     // Initialize the receive packet.
        !           504:     //
        !           505: 
        !           506:     receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
        !           507:     receiveTag->PacketType = TYPE_AT_INDICATE;
        !           508:     receiveTag->Connection = Connection;
        !           509:     receiveTag->TransferDataPended = TRUE;
        !           510: 
        !           511: 
        !           512:     //
        !           513:     // Determine how much data remains to be transferred.
        !           514:     //
        !           515: 
        !           516:     BytesToTransfer = DataTotalLength - indicateBytesTransferred;
        !           517:     ASSERT (BytesToTransfer >= 0);
        !           518: 
        !           519:     if (destBytes < BytesToTransfer) {
        !           520: 
        !           521:         //
        !           522:         // If the data overflows the current receive, then make a
        !           523:         // note that we should complete the receive at the end of
        !           524:         // transfer data, but with EOR false.
        !           525:         //
        !           526: 
        !           527:         receiveTag->EndOfMessage = FALSE;
        !           528:         receiveTag->CompleteReceive = TRUE;
        !           529:         BytesToTransfer = destBytes;
        !           530: 
        !           531:     } else if (destBytes == BytesToTransfer) {
        !           532: 
        !           533:         //
        !           534:         // If the data just fills the current receive, then complete
        !           535:         // the receive; EOR depends on whether this is a DOL or not.
        !           536:         //
        !           537: 
        !           538:         receiveTag->EndOfMessage = Last;
        !           539:         receiveTag->CompleteReceive = TRUE;
        !           540: 
        !           541:     } else {
        !           542: 
        !           543:         //
        !           544:         // Complete the receive if this is a DOL.
        !           545:         //
        !           546: 
        !           547:         receiveTag->EndOfMessage = Last;
        !           548:         receiveTag->CompleteReceive = Last;
        !           549: 
        !           550:     }
        !           551: 
        !           552:     //
        !           553:     // if we've got zero bytes left, avoid the TransferData below and
        !           554:     // just deliver.
        !           555:     //
        !           556: 
        !           557:     if (BytesToTransfer <= 0) {
        !           558:         Connection->IndicationInProgress = FALSE;
        !           559:         receiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
        !           560:         receiveTag->TransferDataPended = FALSE;
        !           561:         StTransferDataComplete (
        !           562:                 deviceContext,
        !           563:                 ndisPacket,
        !           564:                 NDIS_STATUS_SUCCESS,
        !           565:                 0);
        !           566: 
        !           567:         return status;
        !           568:     }
        !           569: 
        !           570:     //
        !           571:     // describe the right part of the user buffer to NDIS. If we can't get
        !           572:     // the mdl for the packet, drop it. Bump the request reference count
        !           573:     // so that we know we need to hold open receives until the NDIS transfer
        !           574:     // data requests complete.
        !           575:     //
        !           576: 
        !           577:     SavedCurrentMdl = Connection->CurrentReceiveMdl;
        !           578:     SavedCurrentByteOffset = Connection->ReceiveByteOffset;
        !           579: 
        !           580:     if ((Connection->ReceiveByteOffset == 0) &&
        !           581:         (receiveTag->CompleteReceive)) {
        !           582: 
        !           583:         //
        !           584:         // If we are transferring into the beginning of
        !           585:         // the current MDL, and we will be completing the
        !           586:         // receive after the transfer, then we don't need to
        !           587:         // copy it.
        !           588:         //
        !           589: 
        !           590:         ndisBuffer = (PNDIS_BUFFER)Connection->CurrentReceiveMdl;
        !           591:         bufferChainLength = BytesToTransfer;
        !           592:         Connection->CurrentReceiveMdl = NULL;
        !           593:         Connection->ReceiveByteOffset = 0;
        !           594:         receiveTag->AllocatedNdisBuffer = FALSE;
        !           595:         tmpstatus = STATUS_SUCCESS;
        !           596: 
        !           597:     } else {
        !           598: 
        !           599:         tmpstatus = BuildBufferChainFromMdlChain (
        !           600:                     deviceContext->NdisBufferPoolHandle,
        !           601:                     Connection->CurrentReceiveMdl,
        !           602:                     Connection->ReceiveByteOffset,
        !           603:                     BytesToTransfer,
        !           604:                     &ndisBuffer,
        !           605:                     &Connection->CurrentReceiveMdl,
        !           606:                     &Connection->ReceiveByteOffset,
        !           607:                     &bufferChainLength);
        !           608: 
        !           609:         receiveTag->AllocatedNdisBuffer = TRUE;
        !           610: 
        !           611:     }
        !           612: 
        !           613: 
        !           614:     if ((!NT_SUCCESS (tmpstatus)) || (bufferChainLength != BytesToTransfer)) {
        !           615: 
        !           616:         DumpData[0] = bufferChainLength;
        !           617:         DumpData[1] = BytesToTransfer;
        !           618: 
        !           619:         StWriteGeneralErrorLog(
        !           620:             deviceContext,
        !           621:             EVENT_TRANSPORT_TRANSFER_DATA,
        !           622:             604,
        !           623:             tmpstatus,
        !           624:             NULL,
        !           625:             2,
        !           626:             DumpData);
        !           627: 
        !           628:         StDereferenceRequest ("No MDL chain", Connection->CurrentReceiveRequest);
        !           629: 
        !           630:         //
        !           631:         // Restore our old state.
        !           632:         //
        !           633: 
        !           634:         Connection->CurrentReceiveMdl = SavedCurrentMdl;
        !           635:         Connection->ReceiveByteOffset = SavedCurrentByteOffset;
        !           636: 
        !           637:         Connection->IndicationInProgress = FALSE;
        !           638: 
        !           639:         ExInterlockedPushEntryList(
        !           640:             &deviceContext->ReceivePacketPool,
        !           641:             (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
        !           642:             &deviceContext->Interlock);
        !           643: 
        !           644:         return status;
        !           645:     }
        !           646: 
        !           647:     NdisChainBufferAtFront (ndisPacket, ndisBuffer);
        !           648: 
        !           649:     //
        !           650:     // set up async return status so we can tell when it has happened;
        !           651:     // can never get return of NDIS_STATUS_PENDING in synch completion routine
        !           652:     // for NdisTransferData, so we know it has completed when this status
        !           653:     // changes
        !           654:     //
        !           655: 
        !           656:     receiveTag->NdisStatus = NDIS_STATUS_PENDING;
        !           657: 
        !           658:     //
        !           659:     // update the number of bytes received; OK to do this
        !           660:     // unprotected since IndicationInProgress is still FALSE.
        !           661:     //
        !           662:     //
        !           663: 
        !           664:     Connection->MessageBytesReceived += BytesToTransfer;
        !           665: 
        !           666:     //
        !           667:     // We have now updated all the connection counters (BUG,
        !           668:     // assuming the TransferData will succeed) and this
        !           669:     // packet's location in the request is secured, so we
        !           670:     // can be reentered.
        !           671:     //
        !           672: 
        !           673:     Connection->IndicationInProgress = FALSE;
        !           674: 
        !           675:     NdisTransferData (
        !           676:         &ndisStatus,
        !           677:         deviceContext->NdisBindingHandle,
        !           678:         ReceiveContext,
        !           679:         sizeof (ST_HEADER) + indicateBytesTransferred,
        !           680:         BytesToTransfer,
        !           681:         ndisPacket,
        !           682:         (PUINT)&ndisBytesTransferred);
        !           683: 
        !           684:     //
        !           685:     // handle the various completion codes
        !           686:     //
        !           687: 
        !           688:     switch (ndisStatus) {
        !           689: 
        !           690:     case NDIS_STATUS_SUCCESS:
        !           691: 
        !           692:         receiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
        !           693:         if (ndisBytesTransferred != BytesToTransfer) {       // Did we get the entire packet?
        !           694: 
        !           695:             DumpData[0] = ndisBytesTransferred;
        !           696:             DumpData[1] = BytesToTransfer;
        !           697: 
        !           698:             StWriteGeneralErrorLog(
        !           699:                 deviceContext,
        !           700:                 EVENT_TRANSPORT_TRANSFER_DATA,
        !           701:                 604,
        !           702:                 ndisStatus,
        !           703:                 NULL,
        !           704:                 2,
        !           705:                 DumpData);
        !           706: 
        !           707:             if (receiveTag->AllocatedNdisBuffer) {
        !           708:                 NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
        !           709:                 while (ndisBuffer != NULL) {
        !           710:                     NdisFreeBuffer (ndisBuffer);
        !           711:                     NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
        !           712:                 }
        !           713:             } else {
        !           714:                 NdisReinitializePacket (ndisPacket);
        !           715:             }
        !           716: 
        !           717:             ExInterlockedPushEntryList(
        !           718:                 &deviceContext->ReceivePacketPool,
        !           719:                 (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
        !           720:                 &deviceContext->Interlock);
        !           721: 
        !           722:             StDereferenceRequest ("Bad byte count", Connection->CurrentReceiveRequest);
        !           723: 
        !           724:             //
        !           725:             // Restore our old state.
        !           726:             //
        !           727: 
        !           728:             Connection->CurrentReceiveMdl = SavedCurrentMdl;
        !           729:             Connection->ReceiveByteOffset = SavedCurrentByteOffset;
        !           730:             Connection->MessageBytesReceived -= BytesToTransfer;
        !           731: 
        !           732:             return status;
        !           733:         }
        !           734: 
        !           735:         //
        !           736:         // deallocate the buffers and such that we've used if at indicate
        !           737:         //
        !           738: 
        !           739:         receiveTag->TransferDataPended = FALSE;
        !           740: 
        !           741:         StTransferDataComplete (
        !           742:                 deviceContext,
        !           743:                 ndisPacket,
        !           744:                 ndisStatus,
        !           745:                 BytesToTransfer);
        !           746:         break;
        !           747: 
        !           748:     case NDIS_STATUS_PENDING:   // waiting async complete from NdisTransferData
        !           749: 
        !           750:         //
        !           751:         // Because TransferDataPended stays TRUE, this reference will
        !           752:         // be removed in TransferDataComplete. It is OK to do this
        !           753:         // now, even though TransferDataComplete may already have been
        !           754:         // called, because we also hold the ProcessIIndicate reference
        !           755:         // so there will be no "bounce".
        !           756:         //
        !           757: 
        !           758:         StReferenceConnection ("TransferData pended", Connection);
        !           759:         break;
        !           760: 
        !           761:     default:
        !           762: 
        !           763:         //
        !           764:         // Something broke; certainly we'll never get NdisTransferData
        !           765:         // asynch completion.
        !           766:         //
        !           767:         // BUGBUG: The driver should recover from this situation.
        !           768:         //
        !           769: 
        !           770:         StWriteGeneralErrorLog(
        !           771:             deviceContext,
        !           772:             EVENT_TRANSPORT_TRANSFER_DATA,
        !           773:             604,
        !           774:             ndisStatus,
        !           775:             NULL,
        !           776:             0,
        !           777:             NULL);
        !           778: 
        !           779:         if (receiveTag->AllocatedNdisBuffer) {
        !           780:             NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
        !           781:             while (ndisBuffer != NULL) {
        !           782:                 NdisFreeBuffer (ndisBuffer);
        !           783:                 NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
        !           784:             }
        !           785:         } else {
        !           786:             NdisReinitializePacket (ndisPacket);
        !           787:         }
        !           788: 
        !           789:         ExInterlockedPushEntryList(
        !           790:             &deviceContext->ReceivePacketPool,
        !           791:             (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
        !           792:             &deviceContext->Interlock);
        !           793: 
        !           794:         StDereferenceRequest ("TransferData failed", Connection->CurrentReceiveRequest);
        !           795: 
        !           796:         //
        !           797:         // Restore our old state.
        !           798:         //
        !           799: 
        !           800:         Connection->CurrentReceiveMdl = SavedCurrentMdl;
        !           801:         Connection->ReceiveByteOffset = SavedCurrentByteOffset;
        !           802:         Connection->MessageBytesReceived -= BytesToTransfer;
        !           803: 
        !           804:         return status;
        !           805:     } // switch ndisStatus
        !           806: 
        !           807:     return status;  // which only means we've dealt with the packet
        !           808: 
        !           809: }   /* ProcessIIndicate */

unix.superglobalmegacorp.com

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