NDIS_STATUS NdisuioReceive( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID pHeaderBuffer, IN UINT HeaderBufferSize, IN PVOID pLookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: Our protocol receive handler called by NDIS, typically if we have a miniport below that doesn't indicate packets. We make a local packet/buffer copy of this data, queue it up, and kick off the read service routine. Arguments: ProtocolBindingContext - pointer to open context MacReceiveContext - for use in NdisTransferData pHeaderBuffer - pointer to data header HeaderBufferSize - size of the above pLookaheadBuffer - pointer to buffer containing lookahead data LookaheadBufferSize - size of the above PacketSize - size of the entire packet, minus header size. Return Value: NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting NDIS_STATUS_SUCCESS - if we processed this successfully --*/ { PNDISUIO_OPEN_CONTEXT pOpenContext; NDIS_STATUS Status; PNDISUIO_ETH_HEADER pEthHeader; PNDIS_PACKET pRcvPacket; PUCHAR pRcvData; UINT BytesTransferred; PNDIS_BUFFER pOriginalNdisBuffer, pPartialNdisBuffer; PIRP pIrp; PLIST_ENTRY pIrpEntry; ULONG BytesRemaining; // at pDst PPACKET_GROUP pGroup; //ULONG pDst; pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext; NUIO_STRUCT_ASSERT(pOpenContext, oc); pRcvPacket = NULL; pRcvData = NULL; Status = NDIS_STATUS_SUCCESS; DEBUGP(DL_LOUD, ("Receive: Open %p, LookaheadBufferSize %d, PacketSize %d\n", pOpenContext, LookaheadBufferSize, PacketSize)); NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->ReceivedPackets, 1); do { if (HeaderBufferSize != sizeof(NDISUIO_ETH_HEADER)) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } pEthHeader = (PNDISUIO_ETH_HEADER)pHeaderBuffer; NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); // // Someone is reading, and this is the first packet. // if (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) && NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { // // Get the first pended Read IRP // pIrpEntry = pOpenContext->PendedReads.Flink; pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry); // // We don't have to worry about the situation where the IRP is cancelled // after we remove it from the queue and before we reset the cancel // routine because the cancel routine has been coded to cancel an IRP // only if it's in the queue. // IoSetCancelRoutine(pIrp, NULL); NUIO_REMOVE_ENTRY_LIST(pIrpEntry); pOpenContext->PendedReadCount--; NUIO_RELEASE_LOCK(&pOpenContext->Lock); NUIO_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet // // Copy as much data as possible from the receive packet to // the IRP MDL. // #ifndef WIN9X pGroup = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); //NUIO_ASSERT(pDst != NULL); // since it was already mapped #else pGroup = MmGetSystemAddressForMdl(pIrp->MdlAddress); // Win9x #endif BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress); BytesRemaining -= sizeof(PACKET_GROUP); // // copy the ethernet header into the actual readbuffer // NdisMoveMappedMemory(pGroup->Data, pHeaderBuffer, HeaderBufferSize); if (PacketSize == LookaheadBufferSize) { BytesTransferred = MIN(LookaheadBufferSize, BytesRemaining); NdisCopyLookaheadData(pGroup->Data + HeaderBufferSize, pLookaheadBuffer, BytesTransferred, pOpenContext->MacOptions); pGroup->Length = BytesTransferred + HeaderBufferSize; pIrp->IoStatus.Information = pGroup->Length + sizeof(PACKET_GROUP); pIrp->IoStatus.Status = STATUS_SUCCESS; DEBUGP(DL_LOUD, ("Receive: %d bytes\n", pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); } else { BytesTransferred = 0; NdisAllocatePacket( &Status, &pRcvPacket, pOpenContext->RecvBufferPool ); if (Status != NDIS_STATUS_SUCCESS) goto ERROR; // // Allocate an MDL to map the portion of the buffer following the // header // pPartialNdisBuffer = IoAllocateMdl(pGroup->Data, BytesRemaining, FALSE, FALSE, NULL); if (pPartialNdisBuffer == NULL) { NdisFreePacket(pRcvPacket); Status = NDIS_STATUS_RESOURCES; goto ERROR; } // // Build the mdl to point to the the portion of the buffer following // the header // IoBuildPartialMdl( pIrp->MdlAddress, pPartialNdisBuffer, pGroup->Data + HeaderBufferSize, 0); // // Clear the next link in the new MDL // pPartialNdisBuffer->Next = NULL; // // Get a pointer to the packet itself. // NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = pIrp; NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pPartialNdisBuffer; // // Attach our partial MDL to the packet // NdisChainBufferAtFront(pRcvPacket, pPartialNdisBuffer); // // Call the Mac to transfer the packet // NdisTransferData( &Status, pOpenContext->BindingHandle, MacReceiveContext, 0, // ByteOffset PacketSize, pRcvPacket, &BytesTransferred); ERROR: // // If it didn't pend, call the completeion routine now // if (Status != NDIS_STATUS_PENDING) { NdisuioTransferDataComplete( (NDIS_HANDLE)pOpenContext, pRcvPacket, Status, BytesTransferred); } } break; } NUIO_RELEASE_LOCK(&pOpenContext->Lock); // // Allocate resources for queueing this up. // pRcvPacket = ndisuioAllocateReceivePacket( pOpenContext, PacketSize + HeaderBufferSize, &pRcvData ); if (pRcvPacket == NULL) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize); // // Check if the entire packet is within the lookahead. // if (PacketSize == LookaheadBufferSize) { NdisCopyLookaheadData(pRcvData + HeaderBufferSize, pLookaheadBuffer, LookaheadBufferSize, pOpenContext->MacOptions); // // Queue this up for receive processing, and // try to complete some read IRPs. // ndisuioQueueReceivePacket(pOpenContext, pRcvPacket); } else { // // Allocate an NDIS buffer to map the receive area // at an offset "HeaderBufferSize" from the current // start. This is so that NdisTransferData can copy // in at the right point in the destination buffer. // NdisAllocateBuffer( &Status, &pPartialNdisBuffer, pOpenContext->RecvBufferPool, pRcvData + HeaderBufferSize, PacketSize); if (Status == NDIS_STATUS_SUCCESS) { // // Unlink and save away the original NDIS Buffer // that maps the full receive buffer. // NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer); NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer; NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = NULL; // // Link in the partial buffer for NdisTransferData to // operate on. // NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer); DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:" " Pkt %p, OriginalBuf %p, PartialBuf %p\n", pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer)); NdisTransferData( &Status, pOpenContext->BindingHandle, MacReceiveContext, 0, // ByteOffset PacketSize, pRcvPacket, &BytesTransferred); } else { // // Failure handled below in TransferDataComplete. // BytesTransferred = 0; } if (Status != NDIS_STATUS_PENDING) { NdisuioTransferDataComplete( (NDIS_HANDLE)pOpenContext, pRcvPacket, Status, BytesTransferred); } } } while (FALSE); if (Status != NDIS_STATUS_SUCCESS && Status != NDIS_STATUS_PENDING) NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->DroppedPackets, 1); return Status; }
NDIS_STATUS PacketReceiveIndicate ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) { POPEN_INSTANCE open; PIO_STACK_LOCATION irpSp; PIRP irp; PLIST_ENTRY packetListEntry; PNDIS_PACKET pPacket; ULONG sizeToTransfer; NDIS_STATUS status; UINT bytesTransfered = 0; ULONG bufferLength; PPACKET_RESERVED reserved; PMDL pMdl; // DebugPrint(("ReceiveIndicate\n")); open= (POPEN_INSTANCE)ProtocolBindingContext; if (HeaderBufferSize > ETHERNET_HEADER_LENGTH) { return NDIS_STATUS_SUCCESS; } // See if there are any pending read that we can satisfy packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); if (packetListEntry == NULL) { // DebugPrint(("No pending read, dropping packets\n")); return NDIS_STATUS_NOT_ACCEPTED; } reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); pPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); irp = RESERVED(pPacket)->Irp; irpSp = IoGetCurrentIrpStackLocation(irp); // We don't have to worry about the situation where the IRP is cancelled // after we remove it from the queue and before we reset the cancel // routine because the cancel routine has been coded to cancel an IRP // only if it's in the queue. IoSetCancelRoutine(irp, NULL); bufferLength = irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH; sizeToTransfer = (PacketSize < bufferLength) ? PacketSize : bufferLength; NdisMoveMappedMemory( MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority), HeaderBuffer, HeaderBufferSize ); pMdl=IoAllocateMdl( MmGetMdlVirtualAddress(irp->MdlAddress), MmGetMdlByteCount(irp->MdlAddress), FALSE, FALSE, NULL ); if (pMdl == NULL) { // DebugPrint(("Packet: Read-Failed to allocate Mdl\n")); status = NDIS_STATUS_RESOURCES; goto ERROR; } IoBuildPartialMdl( irp->MdlAddress, pMdl, ((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH, 0 ); pMdl->Next = NULL; RESERVED(pPacket)->pMdl=pMdl; NdisChainBufferAtFront(pPacket,pMdl); NdisTransferData( &status, open->AdapterHandle, MacReceiveContext, 0, sizeToTransfer, pPacket, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { return NDIS_STATUS_SUCCESS; } ERROR: PacketTransferDataComplete( open, pPacket, status, bytesTransfered ); return NDIS_STATUS_SUCCESS; }
NTSTATUS PacketAllocate( IN PSERVICE_POINT ServicePoint, IN ULONG PacketLength, IN PDEVICE_CONTEXT DeviceContext, IN UCHAR Type, IN PUCHAR CopyData, IN ULONG CopyDataLength, IN PIO_STACK_LOCATION IrpSp, OUT PNDIS_PACKET *Packet ) { NTSTATUS status; PUCHAR packetData; PNDIS_BUFFER pNdisBuffer; PNDIS_BUFFER pNdisBufferData; PNDIS_PACKET packet; USHORT port; DebugPrint(3, ("PacketAllocate, PacketLength = %d, Numberofpackets = %d\n", PacketLength, NumberOfPackets)); // if(ServicePoint && ServicePoint->SmpState == SMP_SYN_RECV) // return STATUS_INSUFFICIENT_RESOURCES; if(DeviceContext == NULL) { DebugPrint(1, ("[LPX]PacketAllocate: DeviceContext is NULL!!!\n")); return STATUS_INVALID_PARAMETER; } if(DeviceContext->LpxPacketPool == NULL) { DebugPrint(1, ("[LPX]PacketAllocate: DeviceContext->LpxPacketPool is NULL!!!\n")); return STATUS_INVALID_PARAMETER; } NdisAllocatePacket(&status, &packet, DeviceContext->LpxPacketPool); if(status != NDIS_STATUS_SUCCESS) { DebugPrint(1, ("[LPX]PacketAllocate: NdisAllocatePacket Failed!!!\n")); return STATUS_INSUFFICIENT_RESOURCES; } status = NdisAllocateMemory( &packetData, PacketLength ); if(status != NDIS_STATUS_SUCCESS) { DebugPrint(1, ("[LpxSmp]PacketAllocate: Can't Allocate Memory packet.\n")); NdisFreePacket(packet); *Packet = NULL; return status; } NdisAllocateBuffer( &status, &pNdisBuffer, DeviceContext->LpxBufferPool, packetData, PacketLength ); if(!NT_SUCCESS(status)) { NdisFreePacket(packet); *Packet = NULL; NdisFreeMemory(packetData); DebugPrint(1, ("[LPX]PacketAllocate: Can't Allocate Buffer!!!\n")); return status; } switch(Type) { case SEND_TYPE: if(ServicePoint && &ServicePoint->SmpContext) { RtlCopyMemory(&packetData[0], ServicePoint->DestinationAddress.Node, ETHERNET_ADDRESS_LENGTH ); RtlCopyMemory(&packetData[ETHERNET_ADDRESS_LENGTH], ServicePoint->SourceAddress.Node, ETHERNET_ADDRESS_LENGTH ); port = HTONS(ETH_P_LPX); RtlCopyMemory(&packetData[ETHERNET_ADDRESS_LENGTH*2], &port, //&ServicePoint->DestinationAddress.Port, 2 ); } if(CopyDataLength) { NdisAllocateBuffer( &status, &pNdisBufferData, DeviceContext->LpxBufferPool, CopyData, CopyDataLength ); if(!NT_SUCCESS(status)) { NdisFreePacket(packet); *Packet = NULL; NdisFreeMemory(packetData); DebugPrint(1, ("[LPX]PacketAllocate: Can't Allocate Buffer For CopyData!!!\n")); return status; } NdisChainBufferAtFront(packet, pNdisBufferData); } break; case RECEIVE_TYPE: NdisMoveMappedMemory( packetData, CopyData, CopyDataLength ); break; } // RESERVED(packet)->ServicePoint = ServicePoint; RESERVED(packet)->Cloned = 0; RESERVED(packet)->IrpSp = IrpSp; RESERVED(packet)->Type = Type; RESERVED(packet)->LpxSmpHeader = NULL; if(IrpSp == NULL) { DebugPrint(2, ("[LPX] PacketAllocate: No IrpSp\n")) ; } NdisChainBufferAtFront(packet, pNdisBuffer); InterlockedIncrement(&NumberOfPackets); *Packet = packet; return STATUS_SUCCESS; }