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; }
static PMDL OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle, UINT32 dataSize) { PMDL mdl; PVOID data; data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG); if (data == NULL) { return NULL; } mdl = NdisAllocateMdl(ndisHandle, data, dataSize); if (mdl == NULL) { OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); } return mdl; }
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; }
VOID IndicateReceivePacket( __in PTAP_ADAPTER_CONTEXT Adapter, __in PUCHAR packetData, __in const unsigned int packetLength ) { PUCHAR injectBuffer; // // Handle miniport Pause // --------------------- // NDIS 6 miniports implement a temporary "Pause" state normally followed // by the Restart. While in the Pause state it is forbidden for the miniport // to indicate receive NBLs. // // That is: The device interface may be "up", but the NDIS miniport send/receive // interface may be temporarily "down". // // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path // the code below will simply ignore inject packets passed to the driver while // the miniport is in the Paused state. // // The correct implementation is to go ahead and build the NBLs corresponding // to the inject packet - but queue them. When Restart is entered the // queued NBLs would be dequeued and indicated to the host. // if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS) { DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n", MINIPORT_INSTANCE_ID (Adapter))); return; } // Allocate flat buffer for packet data. injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority( Adapter->MiniportAdapterHandle, packetLength, TAP_RX_INJECT_BUFFER_TAG, NormalPoolPriority ); if( injectBuffer) { PMDL mdl; // Copy packet data to flat buffer. NdisMoveMemory (injectBuffer, packetData, packetLength); // Allocate MDL for flat buffer. mdl = NdisAllocateMdl( Adapter->MiniportAdapterHandle, injectBuffer, packetLength ); if( mdl ) { PNET_BUFFER_LIST netBufferList; mdl->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( Adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill mdl, // MDL chain 0, packetLength ); if(netBufferList != NULL) { ULONG receiveFlags = 0; LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL if(KeGetCurrentIrql() == DISPATCH_LEVEL) { receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; } // Set flag indicating that this is an injected packet TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED); netBufferList->MiniportReserved[0] = NULL; netBufferList->MiniportReserved[1] = NULL; // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); netBufferList->SourceHandle = Adapter->MiniportAdapterHandle; // // Indicate the packet // ------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the complete packet including Ethernet header and payload. // NdisMIndicateReceiveNetBufferLists( Adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists receiveFlags ); return; } else { DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); NdisFreeMdl(mdl); NdisFreeMemory(injectBuffer,0,0); } } else { DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); NdisFreeMemory(injectBuffer,0,0); } } else { DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); } }
// IRP_MJ_WRITE callback. NTSTATUS TapDeviceWrite( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success PIO_STACK_LOCATION irpSp;// Pointer to current stack location PTAP_ADAPTER_CONTEXT adapter = NULL; ULONG dataLength; PAGED_CODE(); irpSp = IoGetCurrentIrpStackLocation( Irp ); // // Fetch adapter context for this device. // -------------------------------------- // Adapter pointer was stashed in FsContext when handle was opened. // adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; ASSERT(adapter); // // Sanity checks on state variables // if (!tapAdapterReadAndWriteReady(adapter)) { //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", // MINIPORT_INSTANCE_ID (adapter))); //NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } // Save IRP-accessible copy of buffer length Irp->IoStatus.Information = irpSp->Parameters.Write.Length; if (Irp->MdlAddress == NULL) { DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } // // Try to get a virtual address for the MDL. // NdisQueryMdl( Irp->MdlAddress, &Irp->AssociatedIrp.SystemBuffer, &dataLength, NormalPagePriority ); if (Irp->AssociatedIrp.SystemBuffer == NULL) { DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } ASSERT(dataLength == irpSp->Parameters.Write.Length); Irp->IoStatus.Information = irpSp->Parameters.Write.Length; // // Handle miniport Pause // --------------------- // NDIS 6 miniports implement a temporary "Pause" state normally followed // by the Restart. While in the Pause state it is forbidden for the miniport // to indicate receive NBLs. // // That is: The device interface may be "up", but the NDIS miniport send/receive // interface may be temporarily "down". // // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path // the code below will perform a "lying send" for write IRPs passed to the // driver while the miniport is in the Paused state. // // The correct implementation is to go ahead and build the NBLs corresponding // to the user-mode write - but queue them. When Restart is entered the // queued NBLs would be dequeued and indicated to the host. // if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) { if (!adapter->m_tun && ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) { PNET_BUFFER_LIST netBufferList; DUMP_PACKET ("IRP_MJ_WRITE ETH", (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length); //===================================================== // If IPv4 packet, check whether or not packet // was truncated. //===================================================== #if PACKET_TRUNCATION_CHECK IPv4PacketSizeVerify ( (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length, FALSE, "RX", &adapter->m_RxTrunc ); #endif (Irp->MdlAddress)->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill Irp->MdlAddress, // MDL chain 0, dataLength ); if(netBufferList != NULL) { LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL // Stash IRP pointer in NBL MiniportReserved[0] field. netBufferList->MiniportReserved[0] = Irp; netBufferList->MiniportReserved[1] = NULL; // BUGBUG!!! Setup for IRP cancel!!! TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); // // Indicate the packet // ------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the complete packet including Ethernet header and payload. // NdisMIndicateReceiveNetBufferLists( adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists 0 // ReceiveFlags ); ntStatus = STATUS_PENDING; } else { DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) { PETH_HEADER p_UserToTap = &adapter->m_UserToTap; PMDL mdl; // Head of MDL chain. // For IPv6, need to use Ethernet header with IPv6 proto if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 ) { p_UserToTap = &adapter->m_UserToTap_IPv6; } DUMP_PACKET2 ("IRP_MJ_WRITE P2P", p_UserToTap, (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length); //===================================================== // If IPv4 packet, check whether or not packet // was truncated. //===================================================== #if PACKET_TRUNCATION_CHECK IPv4PacketSizeVerify ( (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length, TRUE, "RX", &adapter->m_RxTrunc ); #endif // // Allocate MDL for Ethernet header // -------------------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the only the Ethernet payload. Prepend the user-mode provided // payload with the Ethernet header pointed to by p_UserToTap. // mdl = NdisAllocateMdl( adapter->MiniportAdapterHandle, p_UserToTap, sizeof(ETH_HEADER) ); if(mdl != NULL) { PNET_BUFFER_LIST netBufferList; // Chain user's Ethernet payload behind Ethernet header. mdl->Next = Irp->MdlAddress; (Irp->MdlAddress)->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill mdl, // MDL chain 0, sizeof(ETH_HEADER) + dataLength ); if(netBufferList != NULL) { LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL // This IRP is pended. IoMarkIrpPending(Irp); // This IRP cannot be cancelled while in-flight. IoSetCancelRoutine(Irp,NULL); // Stash IRP pointer in NBL MiniportReserved[0] field. netBufferList->MiniportReserved[0] = Irp; netBufferList->MiniportReserved[1] = NULL; // Set flag indicating that this is P2P packet TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P); // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); // // Indicate the packet // NdisMIndicateReceiveNetBufferLists( adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists 0 // ReceiveFlags ); ntStatus = STATUS_PENDING; } else { mdl->Next = NULL; NdisFreeMdl(mdl); DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else { DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else { DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", MINIPORT_INSTANCE_ID (adapter), irpSp->Parameters.Write.Length)); NOTE_ERROR (); Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; } } else { DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n", MINIPORT_INSTANCE_ID (adapter))); ntStatus = STATUS_SUCCESS; } if (ntStatus != STATUS_PENDING) { Irp->IoStatus.Status = ntStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return ntStatus; }
NDIS_STATUS shared_flush( IN shared_info_t *shared, IN uchar *va, IN ULONG pa, IN ULONG len, IN BOOLEAN writetodevice ) { #ifndef NDIS60 PNDIS_BUFFER b; NDIS_STATUS status; NDIS_PHYSICAL_ADDRESS npa; /* if receive, buffer must begin and end on a cacheline boundary */ if (!writetodevice) { ASSERT(ISALIGNED((uintptr)va, shared->cacheline)); len = ROUNDUP(len, shared->cacheline); } /* alloc a temp buffer descriptor */ NdisAllocateBuffer(&status, &b, shared->rxbufferpool, va, len); if (status != NDIS_STATUS_SUCCESS) { ND_ERROR(("%s%d: shared_flush: NdisAllocateBuffer error 0x%x\n", shared->id, shared->unit, status)); return status; } /* flush processor cache */ NdisAdjustBufferLength(b, len); NdisFlushBuffer(b, writetodevice); npa.HighPart = 0; npa.LowPart = pa; #ifndef USEWDK if (!writetodevice) NdisMUpdateSharedMemory(shared->adapterhandle, len, va, npa); #endif /* USEWDK */ /* free the temp buffer descriptor */ NdisFreeBuffer(b); #else /* NDIS60 */ PMDL b; /* if receive, buffer must begin and end on a cacheline boundary */ if (!writetodevice) { ASSERT(ISALIGNED((uintptr)va, shared->cacheline)); len = ROUNDUP(len, shared->cacheline); } /* alloc a temp MDL */ b = NdisAllocateMdl(shared->adapterhandle, va, len); if (b == NULL) { ND_ERROR(("%s%d: shared_flush: NdisAllocateMdl error\n", shared->id, shared->unit)); return NDIS_STATUS_FAILURE; } /* flush processor cache */ NdisAdjustMdlLength(b, len); NdisFlushBuffer(b, writetodevice); /* free the temp MDL */ NdisFreeMdl(b); #endif /* NDIS60 */ return NDIS_STATUS_SUCCESS; }