// Used on PortReturn to free the RX_PACKETs // allocated via BasePortTranslateRxPacketsToRxNBLs VOID BasePortFreeTranslatedRxNBLs( __in PMP_PORT Port, __out PNET_BUFFER_LIST NetBufferLists ) { PNET_BUFFER_LIST currentNetBufferList, nextNetBufferList; PMDL currentMdl, nextMdl; UNREFERENCED_PARAMETER(Port); currentNetBufferList = NetBufferLists; while (currentNetBufferList != NULL) { nextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList); NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList) = NULL; currentMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(currentNetBufferList)); while (currentMdl != NULL) { nextMdl = NDIS_MDL_LINKAGE(currentMdl); // Free the MDL NdisFreeMdl(currentMdl); currentMdl = nextMdl; } // Free the NET_BUFFER and NET_BUFFER_LIST NdisFreeNetBufferList(currentNetBufferList); currentNetBufferList = nextNetBufferList; } }
BOOLEAN ParaNdis_BindRxBufferToPacket( PARANDIS_ADAPTER *pContext, pRxNetDescriptor p) { ULONG i; PMDL *NextMdlLinkage = &p->Holder; for(i = PARANDIS_FIRST_RX_DATA_PAGE; i < p->BufferSGLength; i++) { *NextMdlLinkage = NdisAllocateMdl( pContext->MiniportHandle, p->PhysicalPages[i].Virtual, p->PhysicalPages[i].size); if(*NextMdlLinkage == NULL) goto error_exit; NextMdlLinkage = &(NDIS_MDL_LINKAGE(*NextMdlLinkage)); } *NextMdlLinkage = NULL; return TRUE; error_exit: ParaNdis_UnbindRxBufferFromPacket(p); return FALSE; }
void ParaNdis_UnbindRxBufferFromPacket( pRxNetDescriptor p) { PMDL NextMdlLinkage = p->Holder; while(NextMdlLinkage != NULL) { PMDL pThisMDL = NextMdlLinkage; NextMdlLinkage = NDIS_MDL_LINKAGE(pThisMDL); NdisAdjustMdlLength(pThisMDL, PAGE_SIZE); NdisFreeMdl(pThisMDL); } }
void ParaNdis_UnbindRxBufferFromPacket( pRxNetDescriptor p) { PMDL NextMdlLinkage = p->Holder; ULONG ulPageDescIndex = PARANDIS_FIRST_RX_DATA_PAGE; while(NextMdlLinkage != NULL) { PMDL pThisMDL = NextMdlLinkage; NextMdlLinkage = NDIS_MDL_LINKAGE(pThisMDL); NdisAdjustMdlLength(pThisMDL, p->PhysicalPages[ulPageDescIndex].size); NdisFreeMdl(pThisMDL); ulPageDescIndex++; } }
static void ParaNdis_AdjustRxBufferHolderLength( pRxNetDescriptor p, ULONG ulDataOffset) { PMDL NextMdlLinkage = p->Holder; ULONG ulBytesLeft = p->PacketInfo.dataLength + ulDataOffset; while(NextMdlLinkage != NULL) { ULONG ulThisMdlBytes = min(PAGE_SIZE, ulBytesLeft); NdisAdjustMdlLength(NextMdlLinkage, ulThisMdlBytes); ulBytesLeft -= ulThisMdlBytes; NextMdlLinkage = NDIS_MDL_LINKAGE(NextMdlLinkage); } NETKVM_ASSERT(ulBytesLeft == 0); }
static void ParaNdis_AdjustRxBufferHolderLength( pRxNetDescriptor p, ULONG ulDataOffset) { PMDL NextMdlLinkage = p->Holder; ULONG ulBytesLeft = p->PacketInfo.dataLength + ulDataOffset; ULONG ulPageDescIndex = PARANDIS_FIRST_RX_DATA_PAGE; while(NextMdlLinkage != NULL) { ULONG ulThisMdlBytes = min(p->PhysicalPages[ulPageDescIndex].size, ulBytesLeft); NdisAdjustMdlLength(NextMdlLinkage, ulThisMdlBytes); ulBytesLeft -= ulThisMdlBytes; NextMdlLinkage = NDIS_MDL_LINKAGE(NextMdlLinkage); ulPageDescIndex++; } NETKVM_ASSERT(ulBytesLeft == 0); }
NDIS_STATUS BasePortTranslateRxPacketsToRxNBLs( __in PMP_PORT Port, __in PMP_RX_MSDU PacketList, __out PNET_BUFFER_LIST* NetBufferLists ) { PNET_BUFFER_LIST outputNetBufferList = NULL; PNET_BUFFER_LIST currentNetBufferList, prevNetBufferList = NULL; USHORT fragmentIndex = 0; PMP_RX_MSDU currentPacket = PacketList, nextPacket; PMP_RX_MPDU currentFragment; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_EXTSTA_RECV_CONTEXT osRecvContext; // This is same for ExtAP & ExtSTA PMDL currentMdl, prevMdl = NULL, mdlChain = NULL; ULONG totalLength = 0; *NetBufferLists = NULL; // Convert each PACKET and FRAGMENT to OS structures while (currentPacket != NULL) { nextPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket); // Go through the FRAGMENTs in this PACKET & create an MDL chain mdlChain = NULL; totalLength = 0; for (fragmentIndex = 0; fragmentIndex < MP_RX_MSDU_MPDU_COUNT(currentPacket); fragmentIndex++) { currentFragment = MP_RX_MSDU_MPDU_AT(currentPacket, fragmentIndex); totalLength += MP_RX_MPDU_LENGTH(currentFragment); // Populate the MDL with Fragment contents currentMdl = NdisAllocateMdl(Port->MiniportAdapterHandle, MP_RX_MPDU_DATA(currentFragment), MP_RX_MPDU_LENGTH(currentFragment) ); if (currentMdl == NULL) { MpTrace(COMP_RECV, DBG_SERIOUS, ("Failed to allocate MDL for a MP_RX_MPDU data\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } // Add this to the MDL chain if (mdlChain == NULL) { // Add this to the head mdlChain = currentMdl; } else { NDIS_MDL_LINKAGE(prevMdl) = currentMdl; } prevMdl = currentMdl; } if (ndisStatus != NDIS_STATUS_SUCCESS) { while (mdlChain != NULL) { currentMdl = mdlChain; mdlChain = NDIS_MDL_LINKAGE(currentMdl); // MDL was allocated NdisFreeMdl(currentMdl); } break; } // Allocate the NET_BUFFER_LIST and the NET_BUFFER currentNetBufferList = NdisAllocateNetBufferAndNetBufferList( Port->RxNetBufferListPool, 0, 0, mdlChain, 0, totalLength ); if (currentNetBufferList == NULL) { MpTrace(COMP_SEND, DBG_SERIOUS, ("Failed to allocate NET_BUFFER_LIST for MP_RX_MSDU \n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } // Populate the RX_PACKET MP_NBL_WRAPPED_RX_MSDU(currentNetBufferList) = currentPacket; MP_NBL_SOURCE_PORT(currentNetBufferList) = Port; if (outputNetBufferList == NULL) { outputNetBufferList = currentNetBufferList; } else { NET_BUFFER_LIST_NEXT_NBL(prevNetBufferList) = currentNetBufferList; } // The Next PACKET's NBL would be added after the current PACKET's NBL prevNetBufferList = currentNetBufferList; osRecvContext = MP_RX_MSDU_RECV_CONTEXT(currentPacket); MP_ASSIGN_NDIS_OBJECT_HEADER(osRecvContext->Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_EXTSTA_RECV_CONTEXT_REVISION_1, sizeof(DOT11_EXTSTA_RECV_CONTEXT)); MP_SET_RECEIVE_CONTEXT(currentNetBufferList, osRecvContext); currentPacket = nextPacket; } if (ndisStatus != NDIS_STATUS_SUCCESS) { if (outputNetBufferList != NULL) { BasePortFreeTranslatedRxNBLs(Port, outputNetBufferList); outputNetBufferList = NULL; } } *NetBufferLists = outputNetBufferList; return ndisStatus; }
NDIS_STATUS CopyBytesFromNetBuffer( PNET_BUFFER_KK NetBuffer, PULONG cbDest, PVOID Dest) /*++ Routine Description: Copies the first cbDest bytes from a NET_BUFFER. In order to show how the various data structures fit together, this implementation copies the data by iterating through the MDLs for the NET_BUFFER. The NdisGetDataBuffer API also allows you to copy a contiguous block of data from a NET_BUFFER. Runs at IRQL <= DISPATCH_LEVEL. Arguments: NetBuffer The NB to read cbDest On input, the number of bytes in the buffer Dest On return, the number of bytes actually copied Dest On return, receives the first cbDest bytes of the network frame in NetBuffer Return Value: None. Notes: If the output buffer is larger than the NB's frame size, *cbDest will contain the number of bytes in the frame size. If the output buffer is smaller than the NB's frame size, only the first *cbDest bytes will be copied (the buffer will receive a truncated copy of the frame). --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; // // Start copy from current MDL // PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer); // // Data on current MDL may be offset from start of MDL // ULONG DestOffset = 0; while (DestOffset < *cbDest && CurrentMdl) { // // Map MDL memory to System Address Space. LowPagePriority means mapping may fail if // system is low on memory resources. // PUCHAR SrcMemory = MmGetSystemAddressForMdlSafe(CurrentMdl, LowPagePriority); ULONG Length = MmGetMdlByteCount(CurrentMdl); if (!SrcMemory) { Status = NDIS_STATUS_RESOURCES; break; } if(DestOffset==0) { // // The first MDL segment should be accessed from the current MDL offset // ULONG MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer); SrcMemory += MdlOffset; Length -= MdlOffset; } Length = min(Length, *cbDest-DestOffset); // // Copy Memory // NdisMoveMemory((PUCHAR)Dest+DestOffset, SrcMemory, Length); DestOffset += Length; // // Get next MDL (if any available) // CurrentMdl = NDIS_MDL_LINKAGE(CurrentMdl); } if(Status == NDIS_STATUS_SUCCESS) { *cbDest = DestOffset; } return Status; }
NTSTATUS NdisprotWrite( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Dispatch routine to handle IRP_MJ_WRITE. Arguments: pDeviceObject - pointer to our device object pIrp - Pointer to request packet Return Value: NT status code. --*/ { PIO_STACK_LOCATION pIrpSp; ULONG DataLength; NTSTATUS NtStatus; PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST pNetBufferList; PMDL pMdl; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; PVOID CancelId; ULONG SendFlags = 0; UNREFERENCED_PARAMETER(pDeviceObject); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; do { if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); if (pIrp->MdlAddress == NULL) { DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp)); NtStatus = STATUS_INVALID_PARAMETER; break; } // // Try to get a virtual address for the MDL. // pEthHeader = NULL; NdisQueryMdl(pIrp->MdlAddress, &pEthHeader, &DataLength, NormalPagePriority); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " IRP %p, MDL %p\n", pIrp, pIrp->MdlAddress)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // if (DataLength < sizeof(NDISPROT_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; } if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)" " larger than max frame size (%d)\n", pOpenContext, DataLength, pOpenContext->MaxFrameSize)); NtStatus = STATUS_INVALID_BUFFER_SIZE; break; } if (pEthHeader->EthType != Globals.EthType) { DEBUGP(DL_WARN, ("Write: Failing send with EthType %x\n", pEthHeader->EthType)); NtStatus = STATUS_INVALID_PARAMETER; break; } if (!NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN)) { DEBUGP(DL_WARN, ("Write: Failing with invalid Source address")); NtStatus = STATUS_INVALID_PARAMETER; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } if (pOpenContext->State != NdisprotRunning || pOpenContext->PowerState != NetDeviceStateD0) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_INFO, ("Device is not ready.\n")); NtStatus = STATUS_UNSUCCESSFUL; break; } pMdl = pIrp->MdlAddress; NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL); pNetBufferList = NdisAllocateNetBufferAndNetBufferList( pOpenContext->SendNetBufferListPool, sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta 0, // back fill size pMdl, 0, // Data offset DataLength); if (pNetBufferList == NULL) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } pOpenContext->PendedSendCount++; NPROT_REF_OPEN(pOpenContext); // pended send IoMarkIrpPending(pIrp); // // Initialize the NetBufferList ref count. This NetBufferList will be freed // when this count goes to zero. // NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1; // // We set up a cancel ID on each send NetBufferList (which maps to a Write IRP), // and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendNetBufferLists() to cancel the NetBufferList. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext; pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNetBufferList; pIrp->Tail.Overlay.DriverContext[2] = CancelId; NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp, NdisprotCancelWrite); NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Set a back pointer from the packet to the IRP. // NPROT_IRP_FROM_SEND_NBL(pNetBufferList) = pIrp; NtStatus = STATUS_PENDING; #if SEND_DBG { PUCHAR pData; pData = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority); NPROT_ASSERT(pEthHeader == pData); DEBUGP(DL_VERY_LOUD, ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n", pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength)); DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48)); } #endif // SEND_DBG pNetBufferList->SourceHandle = pOpenContext->BindingHandle; ASSERT (NDIS_MDL_LINKAGE(pMdl) == NULL); SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK; NdisSendNetBufferLists( pOpenContext->BindingHandle, pNetBufferList, NDIS_DEFAULT_PORT_NUMBER, SendFlags); } while (FALSE); if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }