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 LpxReceiveIndication ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: This routine receives control from the physical provider as an indication that a frame has been received on the physical link. This routine is time critical, so we only allocate a buffer and copy the packet into it. We also perform minimal validation on this packet. It gets queued to the device context to allow for processing later. Arguments: BindingContext - The Adapter Binding specified at initialization time. ReceiveContext - A magic cookie for the MAC. HeaderBuffer - pointer to a buffer containing the packet header. HeaderBufferSize - the size of the header. LookaheadBuffer - pointer to a buffer containing the negotiated minimum amount of buffer I get to look at (not including header). LookaheadBufferSize - the size of the above. May be less than asked for, if that's all there is. PacketSize - Overall size of the packet (not including header). Return Value: NDIS_STATUS - status of operation, one of: NDIS_STATUS_SUCCESS if packet accepted, NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol, NDIS_any_other_thing if I understand, but can't handle. --*/ { PDEVICE_CONTEXT deviceContext; PNDIS_PACKET packet; PLPX_RESERVED reserved = NULL; NDIS_STATUS status; UINT bytesTransfered = 0; UINT startOffset = 0; ETHERNET_HEADER ethernetHeader; DebugPrint( 4, ("LpxReceiveIndication, Entered\n") ); deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; // Check to see if the device context is initialized. if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) || FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) { //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); DebugPrint( 1, ("Device is not initialized. Drop packet\n") ); return NDIS_STATUS_NOT_RECOGNIZED; } NDAS_ASSERT( deviceContext->NdisBindingHandle ); // validation if (HeaderBufferSize != ETHERNET_HEADER_LENGTH) { DebugPrint( 1, ("HeaderBufferSize = %x\n", HeaderBufferSize) ); return NDIS_STATUS_NOT_RECOGNIZED; } NdisCopyLookaheadData( ðernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); // Discard 802.2 LLC SNAP field. // // if Ether Type less than 0x0600 ( 1536 ) if (NTOHS(ethernetHeader.Type) < 0x0600 && NTOHS(ethernetHeader.Type) != 0x0060 && // LOOP: Ethernet Loopback NTOHS(ethernetHeader.Type) != 0x0200 && // PUP : Xerox PUP packet NTOHS(ethernetHeader.Type) != 0x0201) { // PUPAP: Xerox PUP address trans packet //NDAS_ASSERT(FALSE); #if __LPX__ NdisCopyLookaheadData( ðernetHeader, &((PUCHAR)LookAheadBuffer)[LENGTH_8022LLCSNAP - 2], ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); #endif PacketSize -= LENGTH_8022LLCSNAP; LookAheadBufferSize -= LENGTH_8022LLCSNAP; startOffset = LENGTH_8022LLCSNAP; NDAS_ASSERT( ethernetHeader.Type != HTONS(ETH_P_LPX) ); } if (ethernetHeader.Type != HTONS(ETH_P_LPX)) { DebugPrint( 4, ("Type = %x\n", ethernetHeader.Type) ); return NDIS_STATUS_NOT_RECOGNIZED; } // DROP PACKET for DEBUGGING!!!! if (PacketRxDropRate) { PacketRxCountForDrop++; if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) { PLPX_HEADER lpxHeader = (PLPX_HEADER)LookAheadBuffer; if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) { DebugPrint( 6, ("[Drop(%x,%x,%x))]\n", NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) ); } DebugPrint( 2, ("D\n") ); return NDIS_STATUS_NOT_RECOGNIZED; } } if (!(RtlEqualMemory(ethernetHeader.DestinationAddress, deviceContext->LocalAddress.Address, ETHERNET_ADDRESS_LENGTH) || RtlEqualMemory(ethernetHeader.DestinationAddress, LpxBroadcastAddress, ETHERNET_ADDRESS_LENGTH))) { DebugPrint( 4, ("LpxReceiveIndication, %02x%02x%02x%02x%02x%02x\n", deviceContext->LocalAddress.Address[0], deviceContext->LocalAddress.Address[1], deviceContext->LocalAddress.Address[2], deviceContext->LocalAddress.Address[3], deviceContext->LocalAddress.Address[4], deviceContext->LocalAddress.Address[5]) ); DebugPrint( 4, ("LpxReceiveIndication, %02x%02x%02x%02x%02x%02x\n", ethernetHeader.DestinationAddress[0], ethernetHeader.DestinationAddress[1], ethernetHeader.DestinationAddress[2], ethernetHeader.DestinationAddress[3], ethernetHeader.DestinationAddress[4], ethernetHeader.DestinationAddress[5]) ); return NDIS_STATUS_NOT_RECOGNIZED; } NDAS_ASSERT( startOffset == 0 ); DebugPrint( 4, ("LpxReceiveIndication, PacketSize = %d, LookAheadBufferSize = %d, LPX_HEADER size = %d\n", PacketSize, LookAheadBufferSize, sizeof(LPX_HEADER)) ); if (LookAheadBufferSize >= sizeof(LPX_HEADER)) { PNDIS_BUFFER firstBuffer; PUCHAR packetData; PLPX_HEADER lpxHeader; USHORT lpxHeaderSize; lpxHeader = (PLPX_HEADER)((PBYTE)LookAheadBuffer + startOffset); if (lpxHeader->DestinationPort == NTOHS(LPXRP_HIX_PORT)) { DebugPrint( 1, ("[LPX] LpxReceiveIndication: DataGram packet arrived.\n") ); } lpxHeaderSize = sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } #endif if (NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) == lpxHeaderSize) { status = RcvPacketAlloc( deviceContext, 0, &packet ); if (status == STATUS_SUCCESS) { reserved = LpxGetReserved(packet); RtlCopyMemory( &reserved->EthernetHeader, ðernetHeader, ETHERNET_HEADER_LENGTH ); reserved->RecvTime = NdasCurrentTime(); RtlCopyMemory( &reserved->LpxHeader, lpxHeader, lpxHeaderSize ); reserved->HeaderCopied = TRUE; reserved->PacketRawDataLength = 0; reserved->PacketRawDataOffset = 0; LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else if (LookAheadBufferSize >= (UINT16)NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK)) { status = RcvPacketAlloc( deviceContext, NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize, &packet ); if (status == STATUS_SUCCESS) { reserved = LpxGetReserved(packet); RtlCopyMemory( &reserved->EthernetHeader, ðernetHeader, ETHERNET_HEADER_LENGTH ); reserved->RecvTime = NdasCurrentTime(); RtlCopyMemory( &reserved->LpxHeader, lpxHeader, lpxHeaderSize ); reserved->HeaderCopied = TRUE; reserved->PacketRawDataLength = NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize; reserved->PacketRawDataOffset = 0; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); packetData = MmGetMdlVirtualAddress( firstBuffer ); NdisCopyLookaheadData( packetData, (PBYTE)LookAheadBuffer + startOffset + lpxHeaderSize, reserved->PacketRawDataLength, deviceContext->MacOptions ); LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else { status = RcvPacketAlloc( deviceContext, startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK), &packet ); if (status == STATUS_SUCCESS) { reserved = LpxGetReserved(packet); RtlCopyMemory( &reserved->EthernetHeader, ðernetHeader, ETHERNET_HEADER_LENGTH ); reserved->RecvTime = NdasCurrentTime(); RtlCopyMemory( &reserved->LpxHeader, lpxHeader, lpxHeaderSize ); reserved->HeaderCopied = TRUE; reserved->PacketRawDataLength = startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); reserved->PacketRawDataOffset = startOffset + lpxHeaderSize; } } } else { PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; NDAS_ASSERT(FALSE); status = RcvPacketAlloc( deviceContext, PacketSize, &packet ); if (status == STATUS_SUCCESS) { reserved = LpxGetReserved(packet); RtlCopyMemory( &reserved->EthernetHeader, ðernetHeader, ETHERNET_HEADER_LENGTH ); reserved->RecvTime = NdasCurrentTime(); reserved->PacketRawDataLength = PacketSize; reserved->PacketRawDataOffset = startOffset; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + reserved->PacketRawDataOffset); RtlZeroMemory( lpxHeader, sizeof(LPX_HEADER) ); reserved->HeaderCopied = FALSE; } } if (status != NDIS_STATUS_SUCCESS) { return NDIS_STATUS_NOT_RECOGNIZED; } NDAS_ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if (deviceContext->NdisBindingHandle) { NdisTransferData( &status, deviceContext->NdisBindingHandle, MacReceiveContext, 0, LpxGetReserved(packet)->PacketRawDataLength, packet, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { NDAS_ASSERT(FALSE); status = NDIS_STATUS_SUCCESS; } else if (status == NDIS_STATUS_SUCCESS) { LpxTransferDataComplete( deviceContext, packet, status, bytesTransfered ); } else { NDAS_ASSERT(FALSE); DebugPrint( 2, ("NdisTransferData() failed. STATUS=%08lx\n", status) ); } } else { status = NDIS_STATUS_NOT_RECOGNIZED; DebugPrint( 2, ("Invalid device status. STATUS=%08lx\n", status) ); } return status; }