static VOID Nbls_DropAllEgress(_In_ const OVS_SWITCH_INFO* pSwitchInfo, _In_ NET_BUFFER_LIST* pNetBufferLists, _In_ ULONG numberOfNetBufferLists, _In_ BOOLEAN dispatch, _In_ BOOLEAN sameSource) { NDIS_STRING filterReason = { 0 }; ULONG returnFlags = 0; NDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO* pForwardDetail = NULL; RtlInitUnicodeString(&filterReason, L"Extension Paused"); returnFlags = (dispatch) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0; returnFlags |= NDIS_RETURN_FLAGS_SWITCH_SINGLE_SOURCE; pForwardDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNetBufferLists); //if NDIS_RECEIVE_FLAGS_SWITCH_SINGLE_SOURCE (when extension paused)=> drop. why? if (sameSource) { _DropSingleSourceEgress(pSwitchInfo, pNetBufferLists, numberOfNetBufferLists, pForwardDetail, filterReason, returnFlags); } //not NDIS_RECEIVE_FLAGS_SWITCH_SINGLE_SOURCE else { _DropMultipleSourcesEgress(pSwitchInfo, pNetBufferLists, pForwardDetail, filterReason, returnFlags); } }
/* * -------------------------------------------------------------------------- * OvsCopyNBLInfo * * Copy NBL info from src to dst * -------------------------------------------------------------------------- */ NDIS_STATUS OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl, POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize, BOOLEAN copyNblInfo) { PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo; NDIS_STATUS status = NDIS_STATUS_SUCCESS; srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl); dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl); if (srcInfo) { #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO status = context->NdisSwitchHandlers. CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0); if (status != NDIS_STATUS_SUCCESS) { return status; } #else dstInfo->SourcePortId = srcInfo->SourcePortId; dstInfo->SourceNicIndex = srcInfo->SourceNicIndex; if (copyNblInfo) { if (srcCtx->flags & OVS_BUFFER_RECV_BUFFER) { NdisCopyReceiveNetBufferListInfo(dstNbl, srcNbl); } else if (srcCtx->flags & OVS_BUFFER_SEND_BUFFER) { NdisCopySendNetBufferListInfo(dstNbl, srcNbl); } } #endif dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe; if (!srcInfo->IsPacketDataSafe && copySize > srcInfo->SafePacketDataSize) { srcInfo->SafePacketDataSize = copySize; } } else { /* * Assume all data are safe */ dstInfo->IsPacketDataSafe = TRUE; dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID; } return status; }
//NOTE: this function does almost the same work as SendIngressBasic./_DropAll_MultipleSourcesIngress(...) //(i.e. except that it calls Nbls_CompleteEgress). TODO: We must refactor. static VOID _DropMultipleSourcesEgress(_In_ const OVS_SWITCH_INFO* pSwitchInfo, _In_ NET_BUFFER_LIST* pNetBufferLists, _In_ const NDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO* pForwardDetail, NDIS_STRING filterReason, ULONG returnFlags) { NDIS_SWITCH_PORT_ID curSourcePort = pForwardDetail->SourcePortId; ULONG numNbls = 0; NET_BUFFER_LIST* pCurNbl = NULL, *pNextNbl = NULL; NET_BUFFER_LIST* pDropNbl = NULL; NET_BUFFER_LIST** ppCurDropNbl = &pDropNbl; for (pCurNbl = pNetBufferLists; pCurNbl != NULL; pCurNbl = pNextNbl) { pNextNbl = NET_BUFFER_LIST_NEXT_NBL(pCurNbl); NET_BUFFER_LIST_NEXT_NBL(pCurNbl) = NULL; pForwardDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pCurNbl); //the first time it will be true. if (curSourcePort == pForwardDetail->SourcePortId) { *ppCurDropNbl = pCurNbl; ppCurDropNbl = &(NET_BUFFER_LIST_NEXT_NBL(pCurNbl)); ++numNbls; } //if source port of pNetBufferLists != source port of pCurNbl => drop? else { OVS_CHECK(pDropNbl); OVS_CHECK(numNbls > 0); pSwitchInfo->switchHandlers.ReportFilteredNetBufferLists(pSwitchInfo->switchContext, &g_extensionGuid, &g_extensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, pDropNbl, &filterReason); /*fwd ext here*/ Nbls_CompleteEgress(pSwitchInfo, pSwitchInfo->pForwardInfo, pDropNbl, returnFlags); numNbls = 1; pDropNbl = pCurNbl; ppCurDropNbl = &(NET_BUFFER_LIST_NEXT_NBL(pCurNbl)); curSourcePort = pForwardDetail->SourcePortId; } } //either way drop? (if paused) pSwitchInfo->switchHandlers.ReportFilteredNetBufferLists(pSwitchInfo->switchContext, &g_extensionGuid, &g_extensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, pDropNbl, &filterReason); Nbls_CompleteEgress(pSwitchInfo, pSwitchInfo->pForwardInfo, pDropNbl, returnFlags); }
static VOID OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl) { PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info; info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl); if (info == NULL) { return; } OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d " "isDataSafe: %s, safeDataSize: %d", nbl, info->NumAvailableDestinations, info->SourcePortId, info->SourceNicIndex, info->IsPacketDataSafe ? "TRUE" : "FALSE", info->IsPacketDataSafe ? 0 : info->SafePacketDataSize); }
static NTSTATUS OvsInjectPacketThroughActions(PNET_BUFFER_LIST pNbl, OVS_TUNNEL_PENDED_PACKET *packet) { NTSTATUS status = STATUS_SUCCESS; OvsIPv4TunnelKey tunnelKey; NET_BUFFER *pNb; ULONG sendCompleteFlags = 0; BOOLEAN dispatch; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail; LOCK_STATE_EX lockState, dpLockState; LIST_ENTRY missedPackets; OvsCompletionList completionList; KIRQL irql; ULONG SendFlags = NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP; OVS_DATAPATH *datapath = NULL; ASSERT(gOvsSwitchContext); datapath = &gOvsSwitchContext->datapath; /* Fill the tunnel key */ status = OvsSlowPathDecapVxlan(pNbl, &tunnelKey); if(!NT_SUCCESS(status)) { goto dropit; } pNb = NET_BUFFER_LIST_FIRST_NB(pNbl); NdisAdvanceNetBufferDataStart(pNb, packet->transportHeaderSize + packet->ipHeaderSize + sizeof(VXLANHdr), FALSE, NULL); /* Most likely (always) dispatch irql */ irql = KeGetCurrentIrql(); /* dispatch is used for datapath lock as well */ dispatch = (irql == DISPATCH_LEVEL) ? NDIS_RWL_AT_DISPATCH_LEVEL : 0; if (dispatch) { sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL; } InitializeListHead(&missedPackets); OvsInitCompletionList(&completionList, gOvsSwitchContext, sendCompleteFlags); { POVS_VPORT_ENTRY vport; UINT32 portNo; OVS_PACKET_HDR_INFO layers; OvsFlowKey key; UINT64 hash; PNET_BUFFER curNb; OvsFlow *flow; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl); /* * XXX WFP packets contain a single NBL structure. * Reassembeled packet "may" have multiple NBs, however, a simple test shows * that the packet still has a single NB (after reassemble) * We still need to check if the Ethernet header of the innet packet is in a single MD */ curNb = NET_BUFFER_LIST_FIRST_NB(pNbl); ASSERT(curNb->Next == NULL); NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, dispatch); /* Lock the flowtable for the duration of accessing the flow */ OvsAcquireDatapathRead(datapath, &dpLockState, NDIS_RWL_AT_DISPATCH_LEVEL); SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL; vport = OvsFindTunnelVportByDstPort(gOvsSwitchContext, htons(tunnelKey.dst_port), OVS_VPORT_TYPE_VXLAN); if (vport == NULL){ status = STATUS_UNSUCCESSFUL; goto unlockAndDrop; } ASSERT(vport->ovsType == OVS_VPORT_TYPE_VXLAN); portNo = vport->portNo; status = OvsExtractFlow(pNbl, portNo, &key, &layers, &tunnelKey); if (status != NDIS_STATUS_SUCCESS) { goto unlockAndDrop; } flow = OvsLookupFlow(datapath, &key, &hash, FALSE); if (flow) { OvsFlowUsed(flow, pNbl, &layers); datapath->hits++; OvsActionsExecute(gOvsSwitchContext, &completionList, pNbl, portNo, SendFlags, &key, &hash, &layers, flow->actions, flow->actionsLen); OvsReleaseDatapath(datapath, &dpLockState); } else { POVS_PACKET_QUEUE_ELEM elem; datapath->misses++; elem = OvsCreateQueueNlPacket(NULL, 0, OVS_PACKET_CMD_MISS, vport, &key, pNbl, curNb, TRUE, &layers); if (elem) { /* Complete the packet since it was copied to user buffer. */ InsertTailList(&missedPackets, &elem->link); OvsQueuePackets(&missedPackets, 1); } else { status = STATUS_INSUFFICIENT_RESOURCES; } goto unlockAndDrop; } NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); } return status; unlockAndDrop: OvsReleaseDatapath(datapath, &dpLockState); NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); dropit: pNbl = OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE); ASSERT(pNbl == NULL); return status; }
/* * -------------------------------------------------------------------------- * OvsFullCopyNBL -- * * Copy the NBL to a new NBL including data. * * Notes: * The NBL can have multiple NBs, but the final result is one NBL. * -------------------------------------------------------------------------- */ PNET_BUFFER_LIST OvsFullCopyNBL(PVOID ovsContext, PNET_BUFFER_LIST nbl, UINT32 headRoom, BOOLEAN copyNblInfo) { POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; POVS_NBL_POOL ovsPool = &context->ovsPool; PNET_BUFFER_LIST newNbl; PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL; POVS_BUFFER_CONTEXT dstCtx, srcCtx; PMDL mdl; NDIS_STATUS status; UINT32 size, totalSize; ULONG copiedSize; UINT16 flags; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo; srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) { OVS_LOG_INFO("src nbl must have ctx initialized"); ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC); return NULL; } nb = NET_BUFFER_LIST_FIRST_NB(nbl); if (NET_BUFFER_NEXT_NB(nb) == NULL) { return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo); } newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool, (UINT16)sizeof (OVS_BUFFER_CONTEXT), (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL); if (newNbl == NULL) { return NULL; } while (nb) { size = NET_BUFFER_DATA_LENGTH(nb); totalSize = MEM_ALIGN_SIZE(size + headRoom); mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize); if (mdl == NULL) { goto nblcopy_error; } newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0); if (newNb == NULL) { OvsFreeMDLAndData(mdl); goto nblcopy_error; } if (firstNb == NULL) { firstNb = newNb; } else { NET_BUFFER_NEXT_NB(prevNb) = newNb; } prevNb = newNb; #ifdef DBG InterlockedIncrement((LONG volatile *)&ovsPool->nbCount); #endif status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL); ASSERT(status == NDIS_STATUS_SUCCESS); status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0, &copiedSize); if (status != NDIS_STATUS_SUCCESS || size != copiedSize) { goto nblcopy_error; } nb = NET_BUFFER_NEXT_NB(nb); } NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb; newNbl->SourceHandle = ovsPool->ndisHandle; status = context->NdisSwitchHandlers. AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl); if (status != NDIS_STATUS_SUCCESS) { goto nblcopy_error; } status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo); if (status != NDIS_STATUS_SUCCESS) { goto nblcopy_error; } dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl); dstInfo->IsPacketDataSafe = TRUE; dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER); flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA | OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT; OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb), OVS_DEFAULT_PORT_NO); #ifdef DBG OvsDumpNetBufferList(nbl); OvsDumpForwardingDetails(nbl); InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount); #endif OVS_LOG_LOUD("newNbl: %p", newNbl); return newNbl; nblcopy_error: while (firstNb) { #ifdef DBG InterlockedDecrement((LONG volatile *)&ovsPool->nbCount); #endif prevNb = firstNb; firstNb = NET_BUFFER_NEXT_NB(prevNb); mdl = NET_BUFFER_FIRST_MDL(prevNb); NET_BUFFER_FIRST_MDL(prevNb) = NULL; NdisFreeNetBuffer(prevNb); OvsFreeMDLAndData(mdl); } NdisFreeNetBufferList(newNbl); OVS_LOG_ERROR("OvsFullCopyNBL failed"); return NULL; }
/* * -------------------------------------------------------------------------- * OvsAllocateVariableSizeNBL -- * * Allocate variable size NBL, the NBL looks like * NBL + NB + Context * MDL + Data * -------------------------------------------------------------------------- */ PNET_BUFFER_LIST OvsAllocateVariableSizeNBL(PVOID ovsContext, UINT32 size, UINT32 headRoom) { PNET_BUFFER_LIST nbl = NULL; POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; POVS_NBL_POOL ovsPool = &context->ovsPool; POVS_BUFFER_CONTEXT ctx; UINT32 realSize; PMDL mdl; NDIS_STATUS status; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info; if (size == 0) { return NULL; } realSize = MEM_ALIGN_SIZE(size + headRoom); mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize); if (mdl == NULL) { return NULL; } nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool, (UINT16)sizeof (OVS_BUFFER_CONTEXT), (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL, mdl, realSize, 0); if (nbl == NULL) { OvsFreeMDLAndData(mdl); return NULL; } nbl->SourceHandle = ovsPool->ndisHandle; status = context->NdisSwitchHandlers. AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl); if (status != NDIS_STATUS_SUCCESS) { /* * do we need to remove mdl from nbl XXX */ OvsFreeMDLAndData(mdl); NdisFreeNetBufferList(nbl); return NULL; } info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl); ASSERT(info); info->IsPacketDataSafe = TRUE; info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID; status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl), size, 0, NULL); ASSERT(status == NDIS_STATUS_SUCCESS); #ifdef DBG InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount); OvsDumpNetBufferList(nbl); OvsDumpForwardingDetails(nbl); #endif ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_FROM_ZERO_SIZE_POOL, size, OVS_DEFAULT_PORT_NO); OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl); return nbl; }
/* * -------------------------------------------------------------------------- * OvsAllocateFixSizeNBL -- * * Allocate fix size NBL which include * NBL + NB + MBL + Data + Context * Please note: * * Forwarding Context is allocated, but forwarding detail information * is not initailized. * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128 * byte). * -------------------------------------------------------------------------- */ PNET_BUFFER_LIST OvsAllocateFixSizeNBL(PVOID ovsContext, UINT32 size, UINT32 headRoom) { PNET_BUFFER_LIST nbl = NULL; POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; POVS_BUFFER_CONTEXT ctx; POVS_NBL_POOL ovsPool = &context->ovsPool; NDIS_STATUS status; UINT32 line; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info; if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) { line = __LINE__; goto allocate_done; } nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool, (UINT16)sizeof (OVS_BUFFER_CONTEXT), (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL); if (nbl == NULL) { line = __LINE__; goto allocate_done; } nbl->SourceHandle = ovsPool->ndisHandle; status = context->NdisSwitchHandlers. AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl); if (status != NDIS_STATUS_SUCCESS) { NdisFreeNetBufferList(nbl); nbl = NULL; line = __LINE__; goto allocate_done; } info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl); ASSERT(info); info->IsPacketDataSafe = TRUE; info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID; status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl), size, 0, NULL); ASSERT(status == NDIS_STATUS_SUCCESS); #ifdef DBG InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount); OvsDumpNetBufferList(nbl); OvsDumpForwardingDetails(nbl); #endif ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); ASSERT(ctx); OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size, OVS_DEFAULT_PORT_NO); line = __LINE__; allocate_done: OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line); return nbl; }
VOID SxLibSendNetBufferListsIngress( _In_ PSX_SWITCH_OBJECT Switch, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ ULONG SendFlags, _In_ ULONG NumInjectedNetBufferLists ) { BOOLEAN dispatch; BOOLEAN sameSource; ULONG sendCompleteFlags; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail; PNET_BUFFER_LIST curNbl, nextNbl; ULONG numNbls = 0; PNET_BUFFER_LIST dropNbl = NULL; PNET_BUFFER_LIST *curDropNbl = &dropNbl; NDIS_SWITCH_PORT_ID curSourcePort; NDIS_STRING filterReason; dispatch = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); sameSource = NDIS_TEST_SEND_FLAG(SendFlags, NDIS_SEND_FLAGS_SWITCH_SINGLE_SOURCE); InterlockedAdd(&Switch->PendingInjectedNblCount, NumInjectedNetBufferLists); KeMemoryBarrier(); if (Switch->DataFlowState != SxSwitchRunning) { RtlInitUnicodeString(&filterReason, L"Extension Paused"); sendCompleteFlags = (dispatch) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0; sendCompleteFlags |= (sameSource) ? NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE : 0; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists); if (sameSource) { for (curNbl = NetBufferLists; curNbl != NULL; curNbl = curNbl->Next) { ++numNbls; } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, fwdDetail->SourcePortId, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, NetBufferLists, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, NetBufferLists, sendCompleteFlags); } else { curSourcePort = fwdDetail->SourcePortId; for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl) { nextNbl = curNbl->Next; curNbl->Next = NULL; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl); if(curSourcePort == fwdDetail->SourcePortId) { *curDropNbl = curNbl; curDropNbl = &(curNbl->Next); ++numNbls; } else { Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, dropNbl, sendCompleteFlags); numNbls = 1; dropNbl = curNbl; curDropNbl = &(curNbl->Next); curSourcePort = fwdDetail->SourcePortId; } } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, dropNbl, sendCompleteFlags); } goto Cleanup; } NdisFSendNetBufferLists(Switch->NdisFilterHandle, NetBufferLists, NDIS_DEFAULT_PORT_NUMBER, SendFlags); Cleanup: return; }
VOID SxLibSendNetBufferListsEgress( _In_ PSX_SWITCH_OBJECT Switch, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ ULONG NumberOfNetBufferLists, _In_ ULONG ReceiveFlags ) { BOOLEAN dispatch, sameSource; NDIS_SWITCH_PORT_ID sourcePortId; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail; ULONG returnFlags; NDIS_SWITCH_PORT_ID curSourcePort; PNET_BUFFER_LIST curNbl, nextNbl; ULONG numNbls; PNET_BUFFER_LIST dropNbl = NULL; PNET_BUFFER_LIST *curDropNbl = &dropNbl; NDIS_STRING filterReason; dispatch = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags); sameSource = NDIS_TEST_RECEIVE_FLAG(ReceiveFlags, NDIS_RECEIVE_FLAGS_SWITCH_SINGLE_SOURCE); if (Switch->DataFlowState != SxSwitchRunning) { RtlInitUnicodeString(&filterReason, L"Extension Paused"); returnFlags = (dispatch) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0; returnFlags |= NDIS_RETURN_FLAGS_SWITCH_SINGLE_SOURCE; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists); if (sameSource) { sourcePortId = fwdDetail->SourcePortId; Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, sourcePortId, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, NumberOfNetBufferLists, NetBufferLists, &filterReason); SxExtStartCompleteNetBufferListsEgress(Switch, Switch->ExtensionContext, NetBufferLists, returnFlags); } else { curSourcePort = fwdDetail->SourcePortId; numNbls = 0; for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl) { nextNbl = curNbl->Next; curNbl->Next = NULL; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl); if(curSourcePort == fwdDetail->SourcePortId) { *curDropNbl = curNbl; curDropNbl = &(curNbl->Next); ++numNbls; } else { Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsEgress(Switch, Switch->ExtensionContext, dropNbl, returnFlags); numNbls = 1; dropNbl = curNbl; curDropNbl = &(curNbl->Next); curSourcePort = fwdDetail->SourcePortId; } } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsEgress(Switch, Switch->ExtensionContext, dropNbl, returnFlags); } goto Cleanup; } NdisFIndicateReceiveNetBufferLists(Switch->NdisFilterHandle, NetBufferLists, NDIS_DEFAULT_PORT_NUMBER, NumberOfNetBufferLists, ReceiveFlags); Cleanup: return; }