VOID NTAPI ScatterGatherSendPacket( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PSCATTER_GATHER_LIST ScatterGather, IN PVOID Context) { PDMA_CONTEXT DmaContext = Context; PLOGICAL_ADAPTER Adapter = DmaContext->Adapter; PNDIS_PACKET Packet = DmaContext->Packet; NDIS_STATUS Status; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = ScatterGather; Status = proSendPacketToMiniport(Adapter, Packet); if (Status != NDIS_STATUS_PENDING) { NDIS_DbgPrint(MAX_TRACE, ("Completing packet.\n")); MiniSendComplete(Adapter, Packet, Status); } ExFreePool(DmaContext); }
/*----------------------------------------------------------------------------*/ VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag) { PNDIS_PACKET prPacket = (PNDIS_PACKET) pvPacket; NDIS_TCP_IP_CHECKSUM_PACKET_INFO rChecksumPktInfo; UINT_8 ucFlag = 0; if (NDIS_GET_PACKET_PROTOCOL_TYPE(prPacket) == NDIS_PROTOCOL_ID_TCP_IP) { rChecksumPktInfo.Value = (UINT_32) NDIS_PER_PACKET_INFO_FROM_PACKET(prPacket, TcpIpChecksumPacketInfo); /* TODO: need to check NIC_CHECKSUM_OFFLOAD from glue_info ?? */ if (rChecksumPktInfo.Transmit.NdisPacketChecksumV4 || rChecksumPktInfo.Transmit.NdisPacketChecksumV6) { /* only apply checksum offload for IPv4 packets */ if (rChecksumPktInfo.Transmit.NdisPacketIpChecksum) { ucFlag |= TX_CS_IP_GEN; } if (rChecksumPktInfo.Transmit.NdisPacketTcpChecksum || rChecksumPktInfo.Transmit.NdisPacketUdpChecksum) { ucFlag |= TX_CS_TCP_UDP_GEN; } } } *pucFlag = ucFlag; } /* kalQueryChksumOffloadParam */
//*********************************************************************************** // Name: MpProcessSGList // // Description: // starts a direct memory access (DMA) scatter/gather operation. // // Return value: // None // // Parameters: // // NOTE: None // ********************************************************************************** VOID MpProcessSGList( IN PDEVICE_OBJECT pDO, IN PIRP pIrp, IN PSCATTER_GATHER_LIST pSGL, IN PVOID Context ) { NDIS_STATUS nStatus; PNDIS_PACKET Packet = (PNDIS_PACKET)Context; PKIP_PACKET_CONTEXT PacketContext = NDIS_PER_PACKET_CONTEXT(Packet); PKIP_NDIS_PROTOCOL pProtocol = PacketContext->pProtocol; PKIP_NDIS_ADAPTER pAdapter = (PKIP_NDIS_ADAPTER)pProtocol->pInterface; PKIP_NDIS_MINIPORT pMiniport = pAdapter->Interface.Miniport; //PNDIS_CO_VC_PTR_BLOCK VcPtr; NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = pSGL; // // Handle Send/SendPacket differently // //MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_PENDING); if (KIP_MINIPORT_TEST_FLAG(pAdapter, fADAPTER_IS_CO)) { //VcPtr = GET_VCPTR_FROM_PACKET(Packet); //(*VcPtr->WCoSendPacketsHandler)(VcPtr->MiniportContext, // &Packet, // 1); //TODO: ASSERT(FALSE); } else if ( pMiniport->Ndis5.MiniportCharacteristics.SendPacketsHandler ) { pMiniport->Ndis5.MiniportCharacteristics.SendPacketsHandler( pAdapter->NdisMiniportAdapterContext, &Packet, 1 ); } else if ( pMiniport->Ndis5.MiniportCharacteristics.SendHandler ){ nStatus = pMiniport->Ndis5.MiniportCharacteristics.SendHandler( pAdapter->NdisMiniportAdapterContext, Packet, 0 ); // if not pending then complete it if (nStatus != NDIS_STATUS_PENDING) { MpSendPacketCompleteHandler( pAdapter, Packet, nStatus ); } } }
//*********************************************************************************** // Name: MpFreeSGList // // Description: // frees sgdma list // // Return value: // None // // Parameters: // // NOTE: None // ********************************************************************************** VOID MpFreeSGList( IN PKIP_NDIS_ADAPTER pAdapter, IN PNDIS_PACKET Packet ) { PSCATTER_GATHER_LIST pSGL; PDMA_ADAPTER SystemAdapterObject = NDIS_GetSystemAdapterObject( pAdapter->NdisMiniportHandle ); pSGL = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo); if ( SystemAdapterObject ){ SystemAdapterObject->DmaOperations->PutScatterGatherList( SystemAdapterObject, pSGL, TRUE ); } if ( (Packet->Private.Flags & NDIS_FLAGS_USES_SG_BUFFER_LIST ) == NDIS_FLAGS_USES_SG_BUFFER_LIST ){ PNPAGED_LOOKASIDE_LIST SGListLookasideList = NDIS_GetSGListLookasideList( pAdapter->NdisMiniportHandle ); Packet->Private.Flags &= ~NDIS_FLAGS_USES_SG_BUFFER_LIST; pSGL = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved); if ( pSGL && SGListLookasideList ){ ExFreeToNPagedLookasideList( SGListLookasideList, pSGL ); } NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved) = NULL; } else if ( ( Packet->Private.Flags & NDIS_FLAGS_DOUBLE_BUFFERED ) == NDIS_FLAGS_DOUBLE_BUFFERED ){ PNDIS_BUFFER NdisBuffer; PVOID NdisBufferVA; Packet->Private.Flags &= ~NDIS_FLAGS_DOUBLE_BUFFERED; NdisBuffer = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved); if ( NdisBuffer ){ NdisBufferVA = MmGetMdlVirtualAddress(NdisBuffer); NdisFreeBuffer( NdisBuffer ); if ( NdisBufferVA ){ ExFreePoolWithTag(NdisBufferVA,MODULE_TAG); } } } }
/* Maps to ReceiverReceiveNetBufferList() in xennet6 */ static NTSTATUS ReceiverReceivePacket( IN PRECEIVER Receiver, OUT PNDIS_PACKET *pPacket, OUT ULONG *pTotFrags ) { struct ethhdr *eh; PNDIS_PACKET work; NDIS_STATUS stat; PNDIS_BUFFER buffer; uint16_t head_flags; UINT buffer_length; ULONG totOctets; ULONG totFrags; PMP_RFD prefixRfd; PMP_RFD headRfd; stat = ReceiverCommonReceiveRfdChain(Receiver, &head_flags, &prefixRfd, &headRfd, &totOctets, &totFrags); if (stat != NDIS_STATUS_SUCCESS) { Receiver->Common.Adapter->RxError++; goto discard; } XM_ASSERT(totFrags > 0); /* There should never be a prefix as we do not enable GSO on the receive path. */ XM_ASSERT(prefixRfd == NULL); NdisDprAllocatePacketNonInterlocked(&stat, &work, Receiver->RecvPacketPool); if (stat != NDIS_STATUS_SUCCESS) { Receiver->nRxDiscards++; goto discard; } NDIS_SET_PACKET_HEADER_SIZE(work, XENNET_PACKET_HDR_SIZE); NdisChainBufferAtFront(work, &headRfd->Mdl); /* Ick: find the ethernet and IP headers so that we can check (a) the MAC address is for us, and (b) whether to indicate RX csum offload. We rely on the fact that netback always puts the ethernet and IP headers in the same fragment. */ buffer = &headRfd->Mdl; buffer_length = buffer->ByteCount; stat = STATUS_UNSUCCESSFUL; if (buffer_length < sizeof(struct ethhdr)) { NdisDprFreePacketNonInterlocked(work); Receiver->nRxDiscards++; goto discard; } Receiver->Common.Adapter->RxGood++; eh = (struct ethhdr *)buffer->MappedSystemVa; stat = NDIS_STATUS_INVALID_PACKET; if (!MacAddressInteresting(eh->dest, Receiver->Common.Adapter)) { Receiver->Common.Adapter->MacMisdirect++; NdisDprFreePacketNonInterlocked(work); goto discard; } if (eh->proto == TPID_IPV4) { BOOLEAN needCsumFixup; NDIS_TCP_IP_CHECKSUM_PACKET_INFO CsumInfo; CsumInfo.Value = 0; needCsumFixup = (head_flags & NETRXF_csum_blank) ? TRUE : FALSE; if (head_flags & NETRXF_data_validated) { struct iphdr *ih = (struct iphdr *)(eh + 1); if (ih->proto == IPPROTO_TCP && Receiver->rx_csum_tcp_offload) { CsumInfo.Receive.NdisPacketTcpChecksumSucceeded = 1; Receiver->nRxCsumOffload++; } else if (ih->proto == IPPROTO_UDP && Receiver->rx_csum_udp_offload) { CsumInfo.Receive.NdisPacketUdpChecksumSucceeded = 1; Receiver->nRxCsumOffload++; } } if (needCsumFixup) { FixupChecksum(work); Receiver->nRxCsumFixup++; } NDIS_PER_PACKET_INFO_FROM_PACKET(work, TcpIpChecksumPacketInfo) = (PVOID)(ULONG_PTR)CsumInfo.Value; } NDIS_SET_PACKET_STATUS(work, NDIS_STATUS_SUCCESS); *pPacket = work; *pTotFrags = totFrags; return NDIS_STATUS_SUCCESS; discard: ReceiverCommonReleaseRfdChain(&Receiver->Common, prefixRfd); ReceiverCommonReleaseRfdChain(&Receiver->Common, headRfd); return stat; }
NDIS_STATUS NTAPI MiniportSend ( IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET Packet, IN UINT Flags ) { PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; NDIS_STATUS status; PSCATTER_GATHER_LIST sgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo); ULONG transmitLength; ULONG transmitBuffer; PNDIS_BUFFER firstBuffer; PVOID firstBufferVa; UINT firstBufferLength, totalBufferLength; PUCHAR runtBuffer; ASSERT(sgList != NULL); ASSERT(sgList->NumberOfElements == 1); ASSERT(sgList->Elements[0].Address.HighPart == 0); ASSERT((sgList->Elements[0].Address.LowPart & 3) == 0); ASSERT(sgList->Elements[0].Length <= MAXIMUM_FRAME_SIZE); NDIS_DbgPrint(MAX_TRACE, ("Sending %d byte packet\n", sgList->Elements[0].Length)); NdisAcquireSpinLock(&adapter->Lock); if (adapter->TxFull) { NDIS_DbgPrint(MIN_TRACE, ("All TX descriptors are full\n")); NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("Sending packet on TX desc %d\n", adapter->CurrentTxDesc)); // // If this is a runt, we need to pad it manually for the RTL8139 // if (sgList->Elements[0].Length < MINIMUM_FRAME_SIZE) { transmitLength = MINIMUM_FRAME_SIZE; transmitBuffer = adapter->RuntTxBuffersPa.LowPart + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); NdisGetFirstBufferFromPacketSafe(Packet, &firstBuffer, &firstBufferVa, &firstBufferLength, &totalBufferLength, NormalPagePriority); if (firstBufferVa == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to get buffer from packet\n")); NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_RESOURCES; } ASSERT(firstBufferLength == totalBufferLength); runtBuffer = adapter->RuntTxBuffers + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); RtlCopyMemory(runtBuffer, firstBufferVa, firstBufferLength); RtlFillMemory(runtBuffer + firstBufferLength, MINIMUM_FRAME_SIZE - firstBufferLength, 0x00); } else { transmitLength = sgList->Elements[0].Length; transmitBuffer = sgList->Elements[0].Address.LowPart; } status = NICTransmitPacket(adapter, adapter->CurrentTxDesc, transmitBuffer, transmitLength); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Transmit packet failed\n")); NdisReleaseSpinLock(&adapter->Lock); return status; } adapter->CurrentTxDesc++; adapter->CurrentTxDesc %= TX_DESC_COUNT; if (adapter->CurrentTxDesc == adapter->DirtyTxDesc) { NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n")); adapter->TxFull = TRUE; } NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_SUCCESS; }
//*********************************************************************************** // Name: MpAllocSGList // // Description: // sends packet via DMA // // Return value: // None // // Parameters: // // NOTE: None // ********************************************************************************** NDIS_STATUS MpAllocSGList( IN PKIP_NDIS_ADAPTER pAdapter, IN PNDIS_PACKET Packet ) { NDIS_STATUS nStatus = NDIS_STATUS_FAILURE; PNDIS_BUFFER Buffer; PVOID pBufferVa; ULONG PacketLength; PDMA_ADAPTER SystemAdapterObject; PDEVICE_OBJECT DeviceObject; PNPAGED_LOOKASIDE_LIST SGListLookasideList = NULL; ULONG ScatterGatherListSize = 0; PVOID pSGList = NULL; KIRQL OldIrql; PVOID SendBuffer = NULL; PNDIS_BUFFER SendNdisBuffer; ULONG nBytesRead = 0; BOOLEAN fbResult; BOOLEAN fbDMAV2; do { SystemAdapterObject = NDIS_GetSystemAdapterObject( pAdapter->NdisMiniportHandle ); if ( SystemAdapterObject == NULL ){ DBGLOG(( LError, "SystemAdapterObject is NULL\n" )); nStatus = NDIS_STATUS_RESOURCES; break; } fbDMAV2 = (SystemAdapterObject->DmaOperations->Size >= sizeof(DMA_OPERATIONS_V2) ); DeviceObject = NDIS_GetMiniportDeviceObject( pAdapter->NdisMiniportHandle ); if ( DeviceObject == NULL ){ DBGLOG(( LError, "DeviceObject is NULL\n" )); nStatus = NDIS_STATUS_RESOURCES; break; } if ( fbDMAV2 ){ SGListLookasideList = NDIS_GetSGListLookasideList( pAdapter->NdisMiniportHandle ); if ( SGListLookasideList == NULL ){ DBGLOG(( LError, "SGListLookasideList is NULL\n" )); nStatus = NDIS_STATUS_RESOURCES; break; } ScatterGatherListSize = NDIS_GetScatterGatherListSize( pAdapter->NdisMiniportHandle ); if ( ScatterGatherListSize == 0 ){ DBGLOG(( LError, "SGListLookasideList is NULL\n" )); nStatus = NDIS_STATUS_RESOURCES; break; } } NdisQueryPacket(Packet, NULL, NULL, &Buffer, &PacketLength); if ( Buffer == NULL ){ DBGLOG(( LError, "Buffer is NULL\n" )); nStatus = NDIS_STATUS_FAILURE; break; } // try to use build sg list interface if ( fbDMAV2 ){ // allocate SG list pSGList = ExAllocateFromNPagedLookasideList( SGListLookasideList ); if ( pSGList != NULL ){ Packet->Private.Flags |= NDIS_FLAGS_USES_SG_BUFFER_LIST; // sg list NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved) = pSGList; // raise irql to dispatch KeRaiseIrql(DISPATCH_LEVEL,&OldIrql); nStatus = SystemAdapterObject->DmaOperations->BuildScatterGatherList( SystemAdapterObject, DeviceObject, Buffer, MmGetMdlVirtualAddress(Buffer), PacketLength, MpProcessSGList, Packet, TRUE, pSGList, ScatterGatherListSize ); KeLowerIrql( OldIrql ); if ( !NT_SUCCESS ( nStatus )){ DBGLOG(( LDebug, "%08X=BuildMdlFromScatterGatherList failed\n",nStatus )); Packet->Private.Flags &= ~NDIS_FLAGS_RESERVED2; // sg list NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = NULL; ExFreeToNPagedLookasideList( SGListLookasideList, pSGList ); } }else{ DBGLOG(( LDebug, "ExAllocateFromNPagedLookasideList failed\n" )); nStatus = NDIS_STATUS_RESOURCES; } } // if ( !fbDMAV2 ) then nStatus = NDIS_STATUS_FAILURE; if ( !NT_SUCCESS ( nStatus )) { // raise irql to dispatch KeRaiseIrql(DISPATCH_LEVEL,&OldIrql); // call DMA nStatus = SystemAdapterObject->DmaOperations->GetScatterGatherList( SystemAdapterObject, DeviceObject, Buffer, MmGetMdlVirtualAddress(Buffer), PacketLength, MpProcessSGList, Packet, TRUE ); KeLowerIrql( OldIrql ); if ( !NT_SUCCESS ( nStatus )){ DBGLOG(( LError, "%08X=GetScatterGatherList failed\n",nStatus )); } } if ( fbDMAV2 && !NT_SUCCESS ( nStatus ) ) { SendBuffer = ExAllocatePoolWithTag( NonPagedPool, PacketLength, MODULE_TAG ); if ( SendBuffer == NULL ){ DBGLOG(( LError, "ExAllocatePoolWithTag failed\n" )); nStatus = NDIS_STATUS_RESOURCES; break; } NdisAllocateBuffer( &nStatus, &SendNdisBuffer, NULL, SendBuffer, PacketLength ); if ( nStatus != NDIS_STATUS_SUCCESS ){ DBGLOG(( LError, "%08X=NdisAllocateBuffer failed\n",nStatus )); break; } //copy data to intermediate buffer fbResult = NDIS_CopyPacketData( Packet, SendBuffer, PacketLength,0, &nBytesRead ); if ( !fbResult || nBytesRead != PacketLength ){ DBGLOG(( LError, "NDIS_CopyPacketData failed\n" )); nStatus = NDIS_STATUS_RESOURCES; break; } Packet->Private.Flags |= NDIS_FLAGS_DOUBLE_BUFFERED; // sg list NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved) = SendBuffer; // raise irql to dispatch KeRaiseIrql(DISPATCH_LEVEL,&OldIrql); // call DMA nStatus = SystemAdapterObject->DmaOperations->GetScatterGatherList( SystemAdapterObject, DeviceObject, SendNdisBuffer, MmGetMdlVirtualAddress(SendNdisBuffer), PacketLength, MpProcessSGList, Packet, TRUE ); KeLowerIrql( OldIrql ); } if ( !NT_SUCCESS ( nStatus ) ){ if ( SendNdisBuffer ){ NdisFreeBuffer( SendNdisBuffer ); } if ( SendBuffer ){ ExFreePoolWithTag( SendBuffer, MODULE_TAG ); } NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved) = NULL; if (KIP_MINIPORT_TEST_FLAG(pAdapter, fADAPTER_IS_CO)) { ASSERT(FALSE); // TODO: //NdisMCoSendComplete(NDIS_STATUS_FAILURE, GET_VCPTR_FROM_PACKET(Packet), Packet); } else { //MpSendPacketCompleteHandler( pAdapter, Packet, NDIS_STATUS_FAILURE ); // we complete it in caller } } } while ( FALSE ); return nStatus; }