//////////////////////////////////////////////////// // 读取封包中的数据 void FltReadPacketData(PNDIS_PACKET pPacket, PUCHAR lpBufferIn, ULONG nNumberToRead, PUINT lpNumberOfRead) { PUCHAR pBuf; ULONG nBufferSize; PNDIS_BUFFER pBufferDes = NULL; // 检查参数 if(pPacket == NULL || lpBufferIn == NULL || nNumberToRead == 0) { if(lpNumberOfRead != NULL) { *lpNumberOfRead = 0; return ; } } // 设置返回数据 *lpNumberOfRead = 0; // 遍历封包中的缓冲区描述表,将数据复制到用户缓冲区 pBufferDes = pPacket->Private.Head; while(pBufferDes != pPacket->Private.Tail && pBufferDes != NULL) { // 获取此缓冲区描述表的缓冲区信息 NdisQueryBufferSafe(pBufferDes, &pBuf, &nBufferSize, NormalPagePriority); if(pBuf == NULL) return; if(nNumberToRead > nBufferSize) // 复制整个缓冲区 { NdisMoveMemory(lpBufferIn + *lpNumberOfRead, pBuf, nBufferSize); nNumberToRead -= nBufferSize; *lpNumberOfRead += nBufferSize; } else // 仅复制剩下的部分 { NdisMoveMemory(lpBufferIn + *lpNumberOfRead, pBuf, nNumberToRead); *lpNumberOfRead += nNumberToRead; return; } // 下一个缓冲区描述表 pBufferDes = pBufferDes->Next; } }
/*----------------------------------------------------------------------------*/ VOID kalCopyFrame(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, OUT PUINT_8 pucDestBuffer) { PNDIS_PACKET prNdisPacket; PNDIS_BUFFER prNdisBuffer, prNextNdisBuffer; UINT u4PacketLen; UINT u4BytesToCopy; PVOID pvMbuf; UINT u4MbufLength; UINT u4BytesCopied; ASSERT(pvPacket); prNdisPacket = (PNDIS_PACKET) pvPacket; NdisQueryPacket(prNdisPacket, NULL, NULL, &prNdisBuffer, &u4PacketLen); u4BytesToCopy = u4PacketLen; u4BytesCopied = 0; while (u4BytesToCopy != 0) { #ifdef NDIS51_MINIPORT NdisQueryBufferSafe(prNdisBuffer, &pvMbuf, &u4MbufLength, HighPagePriority); #else NdisQueryBuffer(prNdisBuffer, &pvMbuf, &u4MbufLength); #endif /* NDIS51_MINIPORT */ if (pvMbuf == (PVOID) NULL) { ASSERT(pvMbuf); break; } NdisMoveMemory((PVOID) pucDestBuffer, pvMbuf, u4MbufLength); u4BytesToCopy -= u4MbufLength; u4BytesCopied += u4MbufLength; pucDestBuffer += u4MbufLength; NdisGetNextBuffer(prNdisBuffer, &prNextNdisBuffer); prNdisBuffer = prNextNdisBuffer; } ASSERT(u4BytesCopied == u4PacketLen); return; }
int filter_packet(int direction, int iface, PNDIS_PACKET packet) { PNDIS_BUFFER buffer; UINT packet_len, buffer_len, hdr_len; int result; void *pointer; struct ether_hdr *ether_hdr; struct ip_hdr *ip_hdr; //lint -e506 -e613 -e774 -e831 -e550 NdisQueryPacket(packet, NULL, NULL, &buffer, &packet_len); if (packet_len < sizeof(struct ether_hdr)) { DBGOUT(("filter_packet: too small packet for ether_hdr! (%u)\n", packet_len)); return FILTER_UNKNOWN; } /* process ether_hdr */ NdisQueryBufferSafe(buffer, ðer_hdr, &buffer_len, LowPagePriority); if (buffer_len < sizeof(struct ether_hdr)) { DBGOUT(("filter_packet: too small buffer for ether_hdr! (%u)\n", buffer_len)); return FILTER_UNKNOWN; } // go to the next header if (buffer_len > sizeof(struct ether_hdr)) { pointer = (char *)ether_hdr + sizeof(struct ether_hdr); buffer_len -= sizeof(struct ether_hdr); } else { // use next buffer in chain NdisGetNextBuffer(buffer, &buffer); NdisQueryBufferSafe(buffer, &pointer, &buffer_len, LowPagePriority); } if (ether_hdr->ether_type == ETHERNET_TYPE_IP) { /* process ip_hdr */ if (buffer_len < sizeof(struct ip_hdr)) { DBGOUT(("filter_packet: too small buffer for ip_hdr! (%u)\n", buffer_len)); return FILTER_UNKNOWN; } ip_hdr = (struct ip_hdr *)pointer; hdr_len = ip_hdr->ip_hl * 4; if (buffer_len < hdr_len) { DBGOUT(("filter_packet: too small buffer for ip_hdr! (%u vs. %u)\n", buffer_len, hdr_len)); return FILTER_UNKNOWN; } // go to the next header if (buffer_len > hdr_len) { pointer = (char *)ip_hdr + hdr_len; buffer_len -= hdr_len; } else { // use next buffer in chain NdisGetNextBuffer(buffer, &buffer); NdisQueryBufferSafe(buffer, &pointer, &buffer_len, LowPagePriority); } result = process_transp(direction, iface, ip_hdr->ip_p, ip_hdr, pointer, buffer_len); if (result != FILTER_ALLOW) return result; } // default behavior return FILTER_ALLOW; }
VOID LpxTransferDataComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransfered ) { PDEVICE_CONTEXT pDeviceContext; PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; USHORT lpxHeaderSize; UNREFERENCED_PARAMETER( BytesTransfered ); pDeviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; if (Status != NDIS_STATUS_SUCCESS) { ASSERT( FALSE ); DebugPrint( 1, ("[LPX] LpxTransferDataComplete error %x\n", Status) ); PacketFree( pDeviceContext, Packet ); return; } if (RESERVED(Packet)->HeaderCopied == FALSE) { NdisQueryPacket( Packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + RESERVED(Packet)->PacketRawDataOffset); 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 RtlCopyMemory( &RESERVED(Packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(Packet)->HeaderCopied = TRUE; RESERVED(Packet)->PacketRawDataLength = RESERVED(Packet)->PacketRawDataOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); RESERVED(Packet)->PacketRawDataOffset += lpxHeaderSize; } lpxHeaderSize = sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(RESERVED(Packet)->LpxHeader.Option, LPX_OPTION_SOURCE_ADDRESS)) { if (!FlagOn(RESERVED(Packet)->LpxHeader.Option, LPX_OPTION_DESTINATION_ADDRESS)) { RtlCopyMemory( RESERVED(Packet)->OptionSourceAddress, RESERVED(Packet)->OptionDestinationAddress, ETHERNET_ADDRESS_LENGTH ); } lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; ASSERT( RtlEqualMemory(RESERVED(Packet)->EthernetHeader.SourceAddress, RESERVED(Packet)->OptionSourceAddress, ETHERNET_ADDRESS_LENGTH) ); } if (FlagOn(RESERVED(Packet)->LpxHeader.Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; ASSERT( RtlEqualMemory(RESERVED(Packet)->EthernetHeader.DestinationAddress, RESERVED(Packet)->OptionDestinationAddress, ETHERNET_ADDRESS_LENGTH) ); } #endif if (NTOHS(RESERVED(Packet)->LpxHeader.PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize != RESERVED(Packet)->PacketRawDataLength - RESERVED(Packet)->PacketRawDataOffset) { ASSERT( FALSE ); PacketFree( pDeviceContext, Packet ); return; } ExInterlockedInsertTailList( &pDeviceContext->PacketInProgressList, &(RESERVED(Packet)->ListEntry), &pDeviceContext->PacketInProgressQSpinLock ); return; }
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; USHORT protocol; PNDIS_PACKET packet; NDIS_STATUS status; UINT bytesTransfered = 0; UINT startOffset = 0; DebugPrint( 4, ("LpxReceiveIndication, Entered\n") ); deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; // // validation // if (HeaderBufferSize != ETHERNET_HEADER_LENGTH) { DebugPrint( 4, ("HeaderBufferSize = %x\n", HeaderBufferSize) ); return NDIS_STATUS_NOT_RECOGNIZED; } RtlCopyMemory( (PUCHAR)&protocol, &((PUCHAR)HeaderBuffer)[12], sizeof(USHORT) ); // // Discard 802.2 LLC SNAP field. // // if Ether Type less than 0x0600 ( 1536 ) // if (NTOHS(protocol) < 0x0600 && protocol != HTONS(0x0060) && // LOOP: Ethernet Loopback protocol != HTONS(0x0200) && // PUP : Xerox PUP packet protocol != HTONS(0x0201)) { // PUPAP: Xerox PUP address trans packet #if __LPX__ NdisCopyLookaheadData( (PUCHAR)&protocol, &((PUCHAR)LookAheadBuffer)[LENGTH_8022LLCSNAP - 2], sizeof(USHORT), deviceContext->MacOptions ); #endif PacketSize -= LENGTH_8022LLCSNAP; LookAheadBufferSize -= LENGTH_8022LLCSNAP; startOffset = LENGTH_8022LLCSNAP; } if (protocol != HTONS(ETH_P_LPX)) { DebugPrint( 4, ("Type = %x\n", protocol) ); return NDIS_STATUS_NOT_RECOGNIZED; } // // Check to see if the device context is initialized. // //ACQUIRE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) || FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) { //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); DebugPrint( 4,("Device is not initialized. Drop packet\n") ); return NDIS_STATUS_NOT_RECOGNIZED; } ASSERT( deviceContext->NdisBindingHandle ); //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); // // DROP PACKET for DEBUGGING!!!! // #if 1 //DBG // Enabled for testing if (PacketRxDropRate) { PacketRxCountForDrop++; if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) { PLPX_HEADER lpxHeader = (PLPX_HEADER)LookAheadBuffer; #if 0 if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) DebugPrint( 1, ("[Drop(%x,%x,%x))]\n", NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) ); #endif DebugPrint( 1, ("D") ); return NDIS_STATUS_NOT_RECOGNIZED; } } #endif 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); 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) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = 0; RESERVED(packet)->PacketRawDataOffset = 0; LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else if (LookAheadBufferSize >= NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK)) { status = RcvPacketAlloc( deviceContext, NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize; RESERVED(packet)->PacketRawDataOffset = 0; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); packetData = MmGetMdlVirtualAddress( firstBuffer ); NdisCopyLookaheadData( packetData, (PBYTE)LookAheadBuffer + startOffset + lpxHeaderSize, RESERVED(packet)->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) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); RESERVED(packet)->PacketRawDataOffset = startOffset + lpxHeaderSize; } } } else { PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; ASSERT( FALSE ); status = RcvPacketAlloc( deviceContext, PacketSize, &packet ); if (status == STATUS_SUCCESS) { RtlCopyMemory( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RESERVED(packet)->PacketRawDataLength = PacketSize; RESERVED(packet)->PacketRawDataOffset = startOffset; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + RESERVED(packet)->PacketRawDataOffset); RtlZeroMemory( lpxHeader, sizeof(LPX_HEADER) ); RESERVED(packet)->HeaderCopied = FALSE; } } if (status != NDIS_STATUS_SUCCESS) { return NDIS_STATUS_NOT_RECOGNIZED; } ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if (deviceContext->NdisBindingHandle) { //ASSERT( FALSE ); NdisTransferData( &status, deviceContext->NdisBindingHandle, MacReceiveContext, 0, //RESERVED(packet)->PacketRawDataOffset, RESERVED(packet)->PacketRawDataLength, packet, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { LPX_ASSERT( FALSE ); status = NDIS_STATUS_SUCCESS; } else if (status == NDIS_STATUS_SUCCESS) { LpxTransferDataComplete( deviceContext, packet, status, bytesTransfered ); } else { LPX_ASSERT( FALSE ); DebugPrint( 1, ("NdisTransferData() failed. STATUS=%08lx\n", status) ); } } else { status = NDIS_STATUS_NOT_RECOGNIZED; DebugPrint( 1, ("Invalid device status. STATUS=%08lx\n", status) ); } return status; }
VOID PacketFree2 ( IN PNDIS_PACKET Packet ) { PLPX_RESERVED reserved = RESERVED(Packet); PUCHAR packetData; PNDIS_BUFFER pNdisBuffer; UINT uiLength; LONG clone; LONG BufferSeq; BOOLEAN allocMiniport = FALSE; PLPX_RESERVED externalReserved; DebugPrint( 3, ("PacketFree reserved->type = %d\n", reserved->Type) ); ASSERT( Packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); switch (reserved->Type) { case LPX_PACKET_TYPE_SEND: clone = InterlockedDecrement( &reserved->Cloned ); if(clone >= 0) { return; } pNdisBuffer = NULL; BufferSeq = 0; NdisUnchainBufferAtFront( Packet, &pNdisBuffer ); while (pNdisBuffer) { // // Assuming the first data buffer comes from user application // the others are created in LPX for padding, etc. // Free the memory of the others. // if (BufferSeq == 0) { #if DBG NdisQueryBufferSafe( pNdisBuffer, &packetData, &uiLength, HighPagePriority ); ASSERT( packetData == (PCHAR)&RESERVED(Packet)->EthernetHeader ); #endif } else if (BufferSeq == 1) { // UserBuffer } else if (BufferSeq == 2) { // Padding NdisQueryBufferSafe( pNdisBuffer, &packetData, &uiLength, HighPagePriority ); LpxFreeMemoryWithLpxTag( packetData ); } else { ASSERT( FALSE ); } NdisFreeBuffer( pNdisBuffer ); pNdisBuffer = NULL; NdisUnchainBufferAtFront( Packet, &pNdisBuffer ); BufferSeq ++; } if (reserved->IrpSp != NULL) { PIRP _Irp = IRP_SEND_IRP( reserved->IrpSp ); ASSERT( reserved->NdisStatus == NDIS_STATUS_SUCCESS || reserved->NdisStatus == NDIS_STATUS_NOT_ACCEPTED || !NT_SUCCESS(reserved->NdisStatus) ); if (!NT_SUCCESS(reserved->NdisStatus)) { _Irp->IoStatus.Status = reserved->NdisStatus; } //INC_IRP_RETRANSMITS( _Irp, reserved->Retransmits ); LpxDereferenceSendIrp( "Destroy packet", reserved->IrpSp, RREF_PACKET ); } else { DebugPrint( 3, ("[LPX] PacketFree: No IrpSp\n") ) ; } break; case LPX_PACKET_TYPE_RECEIVE: // // If the packet allocated by NIC miniport, break here. // if(RESERVED(Packet)->RecvFlags & LPX_RESERVED_RECVFLAG_ALLOC_MINIPORT) { allocMiniport = TRUE; break; } pNdisBuffer = NULL; NdisUnchainBufferAtFront( Packet, &pNdisBuffer ); #if __LPX_STATISTICS__ { LARGE_INTEGER systemTime; KeQuerySystemTime( &systemTime ); RESERVED(Packet)->DeviceContext->NumberOfRecvPackets ++; RESERVED(Packet)->DeviceContext->FreeTimeOfRecvPackets.QuadPart += systemTime.QuadPart - RESERVED(Packet)->RecvTime2.QuadPart; RESERVED(Packet)->DeviceContext->BytesOfRecvPackets.QuadPart += sizeof(LPX_HEADER) + RESERVED(Packet)->PacketRawDataLength; if (RESERVED(Packet)->PacketRawDataLength) { RESERVED(Packet)->DeviceContext->NumberOfLargeRecvPackets ++; RESERVED(Packet)->DeviceContext->FreeTimeOfLargeRecvPackets.QuadPart += systemTime.QuadPart - RESERVED(Packet)->RecvTime2.QuadPart; RESERVED(Packet)->DeviceContext->BytesOfLargeRecvPackets.QuadPart += sizeof(LPX_HEADER) + RESERVED(Packet)->PacketRawDataLength; } else { RESERVED(Packet)->DeviceContext->NumberOfSmallRecvPackets ++; RESERVED(Packet)->DeviceContext->FreeTimeOfSmallRecvPackets.QuadPart += systemTime.QuadPart - RESERVED(Packet)->RecvTime2.QuadPart; RESERVED(Packet)->DeviceContext->BytesOfSmallRecvPackets.QuadPart += sizeof(LPX_HEADER); } } #endif if (pNdisBuffer) { NdisQueryBufferSafe( pNdisBuffer, &packetData, &uiLength, HighPagePriority ); LpxFreeMemoryWithLpxTag( packetData ); NdisFreeBuffer( pNdisBuffer ); } break; default: ASSERT(FALSE); return; } // // Free external protocol reserved context. // externalReserved = ((PLPX_RESERVED)(Packet->ProtocolReserved))->ExternalReserved; if(externalReserved) { NdisFreeMemory(externalReserved, sizeof(LPX_RESERVED), 0); } ASSERT( Packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if(allocMiniport) { // // Return the packet allocated by NIC miniport // NdisReturnPackets(&Packet, 1); } else { NdisFreePacket( Packet ); InterlockedDecrement( &NumberOfAllockPackets ); DebugPrint( 3, ("Packet REALLY Freed NumberOfAllockPackets = %d\n", NumberOfAllockPackets) ); } }
VOID ReadPacket ( PNDIS_PACKET pPacket, PUCHAR pBuffer, ULONG ulBufSize ) /*++ Routine Description: Retrieves the buffer from a buffer descriptor. Arguments: Packet - Pointer to the buffer descriptor. pBuffer - Pointer to the buffer. ulBufSize - Size of the buffer. Return Value: None. Author: xiaonie 2012/07/12 --*/ { PVOID pVA; PNDIS_BUFFER pFirstBuffer, pNextBuffer; ULONG ulTotalLength; ULONG ulLen; PVOID pBuf = NULL; ULONG ulCount = 0; NdisQueryPacket(pPacket, NULL, NULL, &pFirstBuffer, NULL); while (pFirstBuffer != NULL) { NdisQueryBufferSafe(pFirstBuffer, &pVA, &ulLen, NormalPagePriority); if(!pVA) { // memory not enough DbgPrint("pVA == NULL, insufficient memory!\r\n"); break; } if (ulCount + ulLen > ulBufSize) { DbgPrint("ulCount + ulLen(%d) > ulBufSize(%d)\r\n", ulCount + ulLen, ulBufSize); break; } NdisMoveMemory(pBuffer + ulCount, pVA, ulLen); ulCount += ulLen; NdisGetNextBuffer(pFirstBuffer, &pNextBuffer); pFirstBuffer = pNextBuffer; } DbgPrint("ReadPacket: ulBufSize == %d, ulCount == %d\n", ulBufSize, ulCount); return; }
NTSTATUS NdisuioDoFastRead( IN PNDISUIO_OPEN_CONTEXT pOpenContext, IN PIRP pIrp ) /*++ Routine Description: Utility routine to copy received data into user buffers and complete READ IRPs. Arguments: pOpenContext - pointer to open context Return Value: None --*/ { PNDIS_PACKET pRcvPacket; PLIST_ENTRY pRcvPacketEntry; PUCHAR pSrc, pDst; ULONG BytesRemaining; // at pDst PNDIS_BUFFER pNdisBuffer; ULONG BytesAvailable; PPACKET_GROUP pGroup; CCHAR PriorityBoost = IO_NETWORK_INCREMENT; DEBUGP(DL_VERY_LOUD, ("FastRead: open %p/%x\n", pOpenContext, pOpenContext->Flags)); if (NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) return STATUS_UNSUCCESSFUL; // // Copy as much data as possible from the receive packet to // the IRP MDL. // #ifndef WIN9X pGroup = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); NUIO_ASSERT(pGroup != NULL); // since it was already mapped #else pGroup = MmGetSystemAddressForMdl(pIrp->MdlAddress); // Win9x #endif BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress); // // Get the first queued receive packet // pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink; pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry); do { NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry); pOpenContext->RecvPktCount--; NUIO_RELEASE_LOCK(&pOpenContext->Lock); NUIO_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet pNdisBuffer = pRcvPacket->Private.Head; pDst = pGroup->Data; BytesRemaining -= sizeof(PACKET_GROUP); while (BytesRemaining && (pNdisBuffer != NULL)) { #ifndef WIN9X NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority); if (pSrc == NULL) { DEBUGP(DL_FATAL, ("FastRead: Open %p, QueryBuffer failed for buffer %p\n", pOpenContext, pNdisBuffer)); break; } #else NdisQueryBuffer(pNdisBuffer, &pSrc, &BytesAvailable); #endif if (BytesAvailable) { ULONG BytesToCopy = MIN(BytesAvailable, BytesRemaining); NUIO_COPY_MEM(pDst, pSrc, BytesToCopy); BytesRemaining -= BytesToCopy; pDst += BytesToCopy; } NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer); } ndisuioFreeReceivePacket(pOpenContext, pRcvPacket); pGroup->Length = pDst - pGroup->Data; pGroup = (PPACKET_GROUP)pDst; NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); if (NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { PriorityBoost = IO_NO_INCREMENT; break; } pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink; pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry); NdisQueryPacketLength(pRcvPacket, &BytesAvailable); if (BytesRemaining < BytesAvailable + sizeof(PACKET_GROUP)) break; } while (TRUE); NUIO_RELEASE_LOCK(&pOpenContext->Lock); // // Complete the IRP. // pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining; DEBUGP(DL_INFO, ("FastRead: Open %p, IRP %p completed with %d bytes\n", pOpenContext, pIrp, pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, PriorityBoost); return STATUS_SUCCESS; }
/* * Convert the ndis packet chain into an lbuf . */ struct lbuf* shared_txlb_convert(shared_info_t *sh, ND_PKT *p) { #ifndef NDIS60 struct lbuf *lb; PNDIS_BUFFER b, next; uchar *bdata, *buf; uint blen, tot; struct lbfree *txlbfree; ASSERT(p); NdisQueryPacket(p, NULL, NULL, &b, &tot); ASSERT(b); ASSERT(tot <= LBDATASZ); if ((b == NULL) || (tot > LBDATASZ)) return (NULL); txlbfree = &sh->txfree; /* txqueue free buffer count shouldn't go below threshold */ if (txlbfree->count <= TXLB_FREEPOOL_THREHOLD(txlbfree->total)) return (NULL); /* alloc lbuf */ if ((lb = shared_lb_get(sh, txlbfree)) == NULL) return (NULL); /* Adjust for the head room requested */ ASSERT(txlbfree->size > txlbfree->headroom); lb->data += txlbfree->headroom; /* * In case of dongle, make sure the begining of the buffer is * aligned at 32 bytes for DMA efficiency, after inserting * header of 16 bytes later in DHD layer */ if (((uintptr)lb->data % 32) <= 16) lb->data += 16 - (uintptr)lb->data % 32; else lb->data -= (uintptr)lb->data % 32 - 16; buf = lb->data; while (b && tot) { #if defined(NDIS51) NdisQueryBufferSafe(b, &bdata, &blen, NormalPagePriority); #else NdisQueryBuffer(b, &bdata, &blen); #endif /* defined (NDIS51) */ blen = MIN(blen, tot); if (blen) { bcopy(bdata, buf, blen); lb->tail += blen; lb->len += blen; buf += blen; tot -= blen; } NdisGetNextBuffer(b, &next); b = next; } /* save a pointer to the ndis packet for later sendcomplete */ lb->p = p; return (lb); #else /* !NDIS60 */ struct lbuf *lb; PNET_BUFFER nb; PMDL b, next; uint offset; uchar *bdata, *buf; uint blen, tot; struct lbfree *txlbfree; ASSERT(p); tot = 0; for (nb = NET_BUFFER_LIST_FIRST_NB(p); nb; nb = NET_BUFFER_NEXT_NB(nb)) tot += NET_BUFFER_DATA_LENGTH(nb); nb = NET_BUFFER_LIST_FIRST_NB(p); if (nb == NULL) return (NULL); b = NET_BUFFER_CURRENT_MDL(nb); offset = NET_BUFFER_CURRENT_MDL_OFFSET(nb); ASSERT(b); ASSERT(tot <= LBDATASZ); if ((b == NULL) || (tot > LBDATASZ)) return (NULL); txlbfree = &sh->txfree; /* txqueue free buffer count shouldn't go below threshold */ if (txlbfree->count <= TXLB_FREEPOOL_THREHOLD(txlbfree->total)) return (NULL); /* alloc lbuf */ if ((lb = shared_lb_get(sh, txlbfree)) == NULL) return (NULL); #if defined(NDIS60) /* Adjust for the head room requested */ /* ASSERT(txlbfree->size > txlbfree->headroom); */ lb->data += txlbfree->headroom; /* * In case of dongle, make sure the begining of the buffer is * aligned at 32 bytes for DMA efficiency, after inserting * header of 16 bytes later in DHD layer */ if (((uintptr)lb->data % 32) <= 16) lb->data += 16 - (uintptr)lb->data % 32; else lb->data -= (uintptr)lb->data % 32 - 16; #endif /* UNDER_CE && NDIS60 */ buf = lb->data; while (b && tot) { NdisQueryMdl(b, &bdata, &blen, NormalPagePriority); if (bdata == NULL) goto next_mdl; if (blen > offset) { bdata += offset; blen -= offset; } else { offset -= blen; goto next_mdl; } blen = MIN(blen, tot); if (blen) { bcopy(bdata, buf, blen); lb->tail += blen; lb->len += blen; buf += blen; tot -= blen; offset = 0; } next_mdl: NdisGetNextMdl(b, &next); if (!next) { nb = NET_BUFFER_NEXT_NB(nb); if (nb) { next = NET_BUFFER_CURRENT_MDL(nb); offset = NET_BUFFER_CURRENT_MDL_OFFSET(nb); } } b = next; } /* save a pointer to the ndis packet for later sendcomplete */ lb->p = p; return (lb); #endif /* !NDIS60 */ }
VOID ndisprotServiceReads( IN PNDISPROT_OPEN_CONTEXT pOpenContext ) /*++ Routine Description: Utility routine to copy received data into user buffers and complete READ IRPs. Arguments: pOpenContext - pointer to open context Return Value: None --*/ { PIRP pIrp = NULL; PLIST_ENTRY pIrpEntry; PNDIS_PACKET pRcvPacket; PLIST_ENTRY pRcvPacketEntry; PUCHAR pSrc, pDst; ULONG BytesRemaining; // at pDst PNDIS_BUFFER pNdisBuffer; ULONG BytesAvailable; BOOLEAN FoundPendingIrp; DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n", pOpenContext, pOpenContext->Flags)); NPROT_REF_OPEN(pOpenContext); // temp ref - service reads NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) && !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { FoundPendingIrp = FALSE; // // Get the first pended Read IRP // pIrpEntry = pOpenContext->PendedReads.Flink; while (pIrpEntry != &pOpenContext->PendedReads) { pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry); // // Check to see if it is being cancelled. // if (IoSetCancelRoutine(pIrp, NULL)) { // // It isn't being cancelled, and can't be cancelled henceforth. // NPROT_REMOVE_ENTRY_LIST(pIrpEntry); FoundPendingIrp = TRUE; break; // // NOTE: we decrement PendedReadCount way below in the // while loop, to avoid letting through a thread trying // to unbind. // } else { // // The IRP is being cancelled; let the cancel routine handle it. // DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n", pOpenContext, pIrp)); pIrpEntry = pIrpEntry->Flink; } } // // If no pending IRP // if (FoundPendingIrp == FALSE) { break; } // // Get the first queued receive packet // pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink; NPROT_REMOVE_ENTRY_LIST(pRcvPacketEntry); pOpenContext->RecvPktCount --; NPROT_RELEASE_LOCK(&pOpenContext->Lock); NPROT_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet pRcvPacket = NPROT_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry); // // Copy as much data as possible from the receive packet to // the IRP MDL. // pDst = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); __analysis_assume(pDst); NPROT_ASSERT(pDst != NULL); // since it was already mapped BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress); pNdisBuffer = NDIS_PACKET_FIRST_NDIS_BUFFER(pRcvPacket); // // Copy the data in the received packet into the buffer provided by the client. // If the length of the receive packet is greater than length of the given buffer, // we just copy as many bytes as we can. Once the buffer is full, we just discard // the rest of the data, and complete the IRP sucessfully even we only did a partial copy. // while (BytesRemaining && (pNdisBuffer != NULL)) { #ifndef WIN9X NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority); if (pSrc == NULL) { DEBUGP(DL_FATAL, ("ServiceReads: Open %p, QueryBuffer failed for buffer %p\n", pOpenContext, pNdisBuffer)); break; } #else NdisQueryBuffer(pNdisBuffer, &pSrc, &BytesAvailable); #endif if (BytesAvailable) { ULONG BytesToCopy = MIN(BytesAvailable, BytesRemaining); NPROT_COPY_MEM(pDst, pSrc, BytesToCopy); BytesRemaining -= BytesToCopy; pDst += BytesToCopy; } NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer); } // // Complete the IRP. // pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining; DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n", pOpenContext, pIrp, pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); // // Free up the receive packet - back to the miniport if it // belongs to it, else reclaim it (local copy). // if (NdisGetPoolFromPacket(pRcvPacket) != pOpenContext->RecvPacketPool) { NdisReturnPackets(&pRcvPacket, 1); } else { ndisprotFreeReceivePacket(pOpenContext, pRcvPacket); } NPROT_DEREF_OPEN(pOpenContext); // took out pended Read NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); pOpenContext->PendedReadCount--; } NPROT_RELEASE_LOCK(&pOpenContext->Lock); NPROT_DEREF_OPEN(pOpenContext); // temp ref - service reads }
BOOLEAN cdc_ncm_fill_tx_frame(PMP_ADAPTER Adapter,PNDIS_PACKET Packet,PTCB ptcb, NCMDWORD sign) { PMP_USBPIPE usbpipe = Adapter->UsbPipeForNIC; PUSB_CDC_NCM_NTH16 nth16; PUSB_CDC_NCM_NDP16 ndp16; USHORT n = 0, index, ndplen; UINT PacketLength; PNDIS_BUFFER CurrentBuffer = NULL; PVOID VirtualAddress = NULL; UINT CurrentLength; BOOLEAN bResult = TRUE; int maxpacketsize; int max_datagrams; maxpacketsize=usbpipe->InterfaceData->Pipes[usbpipe->BulkPipeOutput].MaximumPacketSize; if (Packet == NULL) { return TRUE; } max_datagrams=usbpipe->tx_max_datagrams; if (0==ptcb->ulSize) { /* fill out the initial 16-bit NTB header */ nth16 = (PUSB_CDC_NCM_NTH16 )memset(tcb_put(ptcb, sizeof(USB_CDC_NCM_NTH16)), 0, sizeof(USB_CDC_NCM_NTH16)); nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); nth16->wHeaderLength = cpu_to_le16(sizeof(USB_CDC_NCM_NTH16)); nth16->wSequence = cpu_to_le16(usbpipe->tx_seq++); /* count total number of frames in this NTB */ ptcb->NumofOrgSendPacket= 0; } NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, &PacketLength); n = ptcb->NumofOrgSendPacket; if(n>=max_datagrams) { ptcb->bRead2Send=1; } while(n<max_datagrams) { /* get the appropriate NDP for this skb */ ndp16 = cdc_ncm_ndp(Adapter, ptcb, sign, PacketLength + usbpipe->tx_modulus + usbpipe->tx_remainder); /* align beginning of next frame */ cdc_ncm_align_tail(ptcb, usbpipe->tx_modulus, usbpipe->tx_remainder, usbpipe->tx_max); /* check if we had enough room left for both NDP and frame */ if (NULL==ndp16 || ptcb->ulSize + PacketLength > usbpipe->tx_max) { if (n == 0) { ptcb->bRead2Send=0; } else { ptcb->bRead2Send = 1; } bResult=FALSE; break; } /* calculate frame number withing this NDP */ ndplen = le16_to_cpu(ndp16->wLength); index = (ndplen - sizeof(USB_CDC_NCM_NDP16)) / sizeof(USB_CDC_NCM_DPE16); /* OK, add this Packet */ ndp16->dpe16[index].wDatagramLength = cpu_to_le16((USHORT)PacketLength); ndp16->dpe16[index].wDatagramIndex = cpu_to_le16((USHORT)ptcb->ulSize); ndp16->wLength = cpu_to_le16(ndplen + sizeof(USB_CDC_NCM_DPE16)); while(CurrentBuffer) { NdisQueryBufferSafe( CurrentBuffer, &VirtualAddress, &CurrentLength, NormalPagePriority); ASSERT(NULL!=VirtualAddress); CurrentLength = min(CurrentLength, PacketLength); if(CurrentLength) { // Copy the data. NdisMoveMemory(tcb_put(ptcb, CurrentLength), VirtualAddress, CurrentLength); PacketLength -= CurrentLength; } NdisGetNextBuffer( CurrentBuffer, &CurrentBuffer); } if(PacketLength){ NdisZeroMemory(tcb_put(ptcb, PacketLength), PacketLength); PacketLength=0; } InsertTailList( &ptcb->ListOrgSendPacket, (PLIST_ENTRY)&Packet->MiniportReserved[0]); ptcb->NumofOrgSendPacket++; /* send now if this NDP is full */ if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) { ptcb->bRead2Send = 1; break; } break; } /* If collected data size is less or equal CDC_NCM_MIN_TX_PKT * bytes, we send buffers as it is. If we get more data, it * would be more efficient for USB HS mobile device with DMA * engine to receive a full size NTB, than canceling DMA * transfer and receiving a short packet. * * This optimization support is pointless if we end up sending * a ZLP after full sized NTBs. */ if (ptcb->bRead2Send==1&&(ptcb->ulSize%maxpacketsize== 0)) memset(tcb_put(ptcb, 1), 0, 1);/* force short packet */ /* set final frame length */ nth16 = (PUSB_CDC_NCM_NTH16 )ptcb->pData; nth16->wBlockLength = cpu_to_le16((USHORT)ptcb->ulSize); return bResult; }
VOID PacketFree( IN PNDIS_PACKET Packet ) { PLPX_RESERVED reserved = RESERVED(Packet); PUCHAR packetData; PNDIS_BUFFER pNdisBuffer; UINT uiLength; LONG clone ; DebugPrint(3, ("PacketFree reserved->type = %d\n", reserved->Type)); switch(reserved->Type) { case SEND_TYPE: clone = InterlockedDecrement(&reserved->Cloned); if(clone >= 0) { return; } pNdisBuffer = NULL; NdisUnchainBufferAtFront(Packet, &pNdisBuffer); if(pNdisBuffer) { NdisQueryBufferSafe( pNdisBuffer, &packetData, &uiLength, HighPagePriority ); NdisFreeMemory(packetData); NdisFreeBuffer(pNdisBuffer); } pNdisBuffer = NULL; NdisUnchainBufferAtFront(Packet, &pNdisBuffer); while(pNdisBuffer) { NdisFreeBuffer(pNdisBuffer); pNdisBuffer = NULL; NdisUnchainBufferAtFront(Packet, &pNdisBuffer); } if(reserved->IrpSp != NULL) { LpxDereferenceSendIrp(reserved->IrpSp); } else { DebugPrint(2, ("[LPX] PacketFree: No IrpSp\n")) ; } break; case RECEIVE_TYPE: if(reserved->LpxSmpHeader) //ExFreePool(reserved->LpxSmpHeader); NdisFreeMemory(reserved->LpxSmpHeader); pNdisBuffer = NULL; NdisUnchainBufferAtFront(Packet, &pNdisBuffer); if(pNdisBuffer) { NdisQueryBufferSafe( pNdisBuffer, &packetData, &uiLength, HighPagePriority ); NdisFreeMemory(packetData); NdisFreeBuffer(pNdisBuffer); } reserved->PacketDataOffset = 0; break; } NdisFreePacket(Packet); InterlockedDecrement(&NumberOfPackets); DebugPrint(2, ("Packet REALLY Freed Numberofpackets = %d\n", NumberOfPackets)); }
struct Send_Packet_Data* Packet2PacketData(PNDIS_PACKET Packet) { UINT buffer_count; PNDIS_BUFFER buffer; UINT packet_len; UINT offset; PVOID addr; UINT len; struct Send_Packet_Data* packet_data; packet_data = NULL; NdisQueryPacket(Packet, NULL, &buffer_count, &buffer, &packet_len); if (!buffer_count || !buffer) goto error_exit; if (buffer_count > 1) { packet_data = PreparePacketData(buffer_count, packet_len); if (!packet_data) goto error_exit; offset = 0; while(1) { NdisQueryBufferSafe(buffer, &addr, &len, NormalPagePriority); if (!addr || !len) goto error_exit; RtlCopyMemory(packet_data->m_data+offset, addr, len); offset += len; NdisGetNextBuffer(buffer, &buffer); if (!buffer) break; } packet_data->m_ndis_packet = Packet; packet_data->m_len = packet_len; } else { packet_data = PreparePacketData(buffer_count, 0); if (!packet_data) goto error_exit; NdisQueryBufferSafe(buffer, &addr, &len, NormalPagePriority); if (!addr || !len) goto error_exit; packet_data->m_ndis_packet = Packet; packet_data->m_len = packet_len; packet_data->m_data = addr; } packet_data->m_mdl = IoAllocateMdl(packet_data->m_data, packet_data->m_len, FALSE, FALSE, NULL); if (!packet_data->m_mdl) goto error_exit; try { MmProbeAndLockPages(packet_data->m_mdl, KernelMode, IoReadAccess); packet_data->m_locked = 1; } except(EXCEPTION_EXECUTE_HANDLER) { packet_data->m_locked = 0; } packet_data->m_addr = MmMapLockedPagesSpecifyCache(packet_data->m_mdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority); if (!packet_data->m_addr) goto error_exit; packet_data->m_map_process = PsGetCurrentProcessId(); return packet_data; error_exit: DbgPrint("Packet2PacketData failed, force to complete the lost packet\n"); free_send_packet_data(packet_data); return NULL; }
INT PacketReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet ) { UINT bytesTransfered = 0; POPEN_INSTANCE open; PIRP irp; PNDIS_PACKET myPacket; PLIST_ENTRY packetListEntry; ULONG bufferLength; PPACKET_RESERVED reserved; PIO_STACK_LOCATION irpSp; PMDL mdl; PVOID startAddress; NTSTATUS status; // DebugPrint(("PacketReceivePacket\n")); open = (POPEN_INSTANCE)ProtocolBindingContext; packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); if (packetListEntry == NULL) { // DebugPrint(("No pending read, dropping packets\n")); return 0; } reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); myPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); irp = RESERVED(myPacket)->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); // Following block of code locks the destination packet // MDLs in a safe manner. This is a temporary workaround // for NdisCopyFromPacketToPacket that currently doesn't use // safe functions to lock pages of MDL. This is required to // prevent system from bugchecking under low memory resources. // { PVOID virtualAddress; PNDIS_BUFFER firstBuffer, nextBuffer; ULONG totalLength; NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength); while( firstBuffer ) { NdisQueryBufferSafe( firstBuffer, &virtualAddress, &totalLength, NormalPagePriority ); if(!virtualAddress) { status = STATUS_INSUFFICIENT_RESOURCES; goto CleanExit; } NdisGetNextBuffer(firstBuffer, &nextBuffer); firstBuffer = nextBuffer; } } NdisChainBufferAtFront( myPacket, irp->MdlAddress ); bufferLength=irpSp->Parameters.Read.Length; NdisCopyFromPacketToPacket( myPacket, 0, bufferLength, Packet, 0, &bytesTransfered ); CleanExit: NdisFreePacket(myPacket); irp->IoStatus.Status = status; irp->IoStatus.Information = bytesTransfered; IoCompleteRequest(irp, IO_NO_INCREMENT); // DebugPrint(("BytesTransfered:%d\n", bytesTransfered)); IoDecrement(open); return 0; }
VOID PtSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) /*++ Routine Description: Called by NDIS when the miniport below had completed a send. We should complete the corresponding upper-edge send this represents. Arguments: ProtocolBindingContext - Points to ADAPT structure Packet - Low level packet being completed Status - status of send Return Value: None --*/ { //------------------------------------------------------------------------- PNDIS_BUFFER packet_buffer; PUCHAR send_buffer = NULL; ULONG send_buffer_length; //------------------------------------------------------------------------- PADAPT pAdapt =(PADAPT)ProtocolBindingContext; PNDIS_PACKET Pkt; NDIS_HANDLE PoolHandle; #ifdef NDIS51 // // Packet stacking: // // Determine if the packet we are completing is the one we allocated. If so, then // get the original packet from the reserved area and completed it and free the // allocated packet. If this is the packet that was sent down to us, then just // complete it // PoolHandle = NdisGetPoolFromPacket(Packet); if (PoolHandle != pAdapt->SendPacketPoolHandle) { // // We had passed down a packet belonging to the protocol above us. // // DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet)); NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status); } else #endif // NDIS51 { PSEND_RSVD SendRsvd; SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved); Pkt = SendRsvd->OriginalPkt; //-------------------WestChamber----------------------------------- if (!Pkt) { //our packet //get buffer NdisUnchainBufferAtFront(Packet, &packet_buffer); if (packet_buffer) { NdisQueryBufferSafe(packet_buffer, (PVOID *)&send_buffer, &send_buffer_length, HighPagePriority); if (send_buffer && send_buffer_length) { //got buffer, free it. NdisFreeMemory(send_buffer, send_buffer_length, 0); } NdisFreeBuffer(packet_buffer); } //free packet NdisDprFreePacket(Packet); return; } //-------------------WestChamber---------------------------------- #ifndef WIN9X NdisIMCopySendCompletePerPacketInfo (Pkt, Packet); #endif NdisDprFreePacket(Packet); NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status); } }
/* We've received a csum_blank packet, but we don't want to let Windows see it like. Calculate the checksum and dump it in the packet. This only works for TCP and UDP on IPv4; on anything else it's a no-op. */ static VOID FixupChecksum(PNDIS_PACKET packet) { PNDIS_BUFFER pbuf; PNDIS_BUFFER pbuf_next; UINT bufLength; UINT len; struct ethhdr *eh; struct iphdr *ih; uint32_t csum_accumulator; uint32_t *ptr; uint16_t *csum_field; NdisQueryPacket(packet, NULL, NULL, &pbuf, NULL); NdisQueryBufferSafe(pbuf, &eh, &bufLength, NormalPagePriority); if (!eh || bufLength < sizeof(*eh)) return; if (eh->proto != TPID_IPV4) { static BOOLEAN warned; if (!warned) { TraceWarning(("Asked to perform checksum calculation on non-IP ethernet prototocol %x!\n", eh->proto)); warned = TRUE; } return; } ih = (struct iphdr *)(eh + 1); bufLength -= sizeof(*eh); if (bufLength < sizeof(*ih) || bufLength < (UINT)(ih->len_version & 0x0f) * 4) return; ptr = (uint32_t *)((ULONG_PTR)ih + (ih->len_version & 0x0f)*4); len = ntohs(ih->tot_len) - (ih->len_version & 0x0f) * 4; bufLength -= (ih->len_version & 0x0f) * 4; if (bufLength > len) bufLength = len; if (ih->proto == IPPROTO_UDP) { if (bufLength < sizeof(struct udphdr)) return; csum_field = &((struct udphdr *)ptr)->checksum; } else if (ih->proto == IPPROTO_TCP) { if (bufLength < sizeof(struct tcphdr)) return; csum_field = &((struct tcphdr *)ptr)->checksum; } else { static BOOLEAN warned; /* Uh oh: don't know what this protocol is, so can't do checksum calculation for it. */ if (!warned) { TraceWarning(("Asked to perform checksum calculation for unknown protocol %d!\n", ih->proto)); warned = TRUE; } return; } if (ih->proto == IPPROTO_TCP) { struct tcp_pseudo_header tph; uint16_t csum; tph.saddr = ih->src; tph.daddr = ih->dest; tph.mbz = 0; tph.ptcl = IPPROTO_TCP; tph.length = htons((uint16_t)len); csum_accumulator = acc_ip_csum(&tph, sizeof(tph), 0); csum = fold_ip_csum(csum_accumulator); if (*csum_field != csum) TraceWarning(("invlid pseudo header checksum: expected %04x, found %04x\n", csum, *csum_field)); *csum_field = csum; } csum_accumulator = acc_ip_csum(ptr, bufLength, 0); len -= bufLength; while (len) { NdisGetNextBuffer(pbuf, &pbuf_next); if (pbuf_next == NULL) break; pbuf = pbuf_next; NdisQueryBufferSafe(pbuf, &ptr, &bufLength, NormalPagePriority); /* The buffer is already mapped into our RX buffer pool, so we should always be able to get a virtual address for it. */ XM_ASSERT(ptr != NULL); if (bufLength > len) bufLength = len; csum_accumulator = acc_ip_csum(ptr, bufLength, csum_accumulator); len -= bufLength; } *csum_field = ~fold_ip_csum(csum_accumulator); }
BOOLEAN PickPacketFromList(PADAPT pAdapt,PIRP Irp) { PIO_STACK_LOCATION IrpStack; ULONG PacketLenTotal=0; PNDIS_PACKET pRcvPacket; PLIST_ENTRY pRcvPacketEntry; PUCHAR pSrc, pDst; PUCHAR pDstFormer; ULONG BytesRemaining; // at pDst PNDIS_BUFFER pNdisBuffer; ULONG BytesAvailable; ULONG BytesToCopy; NdisAcquireSpinLock(&PacketListLock); if(!IsListEmpty(&PacketList)) { // // Get the first queued receive packet // pRcvPacketEntry = PacketList.Flink; RemoveEntryList(pRcvPacketEntry); PacketCount--; NdisReleaseSpinLock(&PacketListLock); pRcvPacket = SECLAB_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry); // // Copy as much data as possible from the receive packet to // the IRP MDL. // pDst = (PUCHAR)ExAllocatePool(NonPagedPool,MY_MTU); if(pDst==NULL) { DbgPrint("Can not allocate enough pool"); DbgBreakPoint(); } pDstFormer=pDst; IrpStack = IoGetCurrentIrpStackLocation(Irp); BytesRemaining = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; pNdisBuffer = pRcvPacket->Private.Head; while (BytesRemaining && (pNdisBuffer != NULL)) { NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority); if (pSrc == NULL) { DbgPrint("PickPacketFromList: QueryBuffer failed for buffer"); break; } if (BytesAvailable) { BytesToCopy = MIN(BytesAvailable, BytesRemaining); NdisMoveMemory(pDstFormer, pSrc, BytesToCopy); BytesRemaining -= BytesToCopy; pDstFormer += BytesToCopy; PacketLenTotal += BytesToCopy; } NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer); } // // Complete the IRP. // RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, pDst, PacketLenTotal); IoSetCancelRoutine(Irp,NULL); CompleteIrp(Irp,STATUS_SUCCESS,PacketLenTotal); ExFreePool(pDst); // // Free up the receive packet - back to the miniport if it // belongs to it, else reclaim it (local copy). // if (NdisGetPoolFromPacket(pRcvPacket) != pAdapt->RecvPacketPoolHandle) { NdisReturnPackets(&pRcvPacket, 1); } else { SecLabFreeReceivePacket(pAdapt, pRcvPacket); } } else { NdisReleaseSpinLock(&PacketListLock); return FALSE; } return TRUE; }