static NDIS_STATUS OvsProcessMethodOid(POVS_SWITCH_CONTEXT switchObject, PNDIS_OID_REQUEST oidRequest, PBOOLEAN complete, PULONG bytesNeededParam) { NDIS_STATUS status = NDIS_STATUS_SUCCESS; struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION); struct _SET *nicReqSetInfo = NULL; PNDIS_OBJECT_HEADER header = NULL; PNDIS_OID_REQUEST nicOidRequest = NULL; UNREFERENCED_PARAMETER(switchObject); OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu", oidRequest, methodInfo->Oid); *complete = FALSE; *bytesNeededParam = 0; header = methodInfo->InformationBuffer; switch(methodInfo->Oid) { /* We deal with only OID_SWITCH_NIC_REQUEST as of now */ case OID_SWITCH_NIC_REQUEST: if (OvsCheckOidHeader(header, NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1)) { OVS_LOG_INFO("Check Header failed"); status = NDIS_STATUS_NOT_SUPPORTED; *complete = TRUE; goto done; } nicOidRequest = (((PNDIS_SWITCH_NIC_OID_REQUEST)header)->OidRequest); nicReqSetInfo = &(nicOidRequest->DATA.SET_INFORMATION); /* Fail the SR-IOV VF case */ if ((nicOidRequest->RequestType == NdisRequestSetInformation) && (nicReqSetInfo->Oid == OID_NIC_SWITCH_ALLOCATE_VF)) { OVS_LOG_INFO("We do not support Oid: " "OID_NIC_SWITCH_ALLOCATE_VF"); status = NDIS_STATUS_FAILURE; *complete = TRUE; } break; default: /* No op */ break; } done: OVS_LOG_TRACE("Exit: status %8x.", status); return status; }
static VOID OvsDumpNBLContext(PNET_BUFFER_LIST nbl) { PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context; if (ctx == NULL) { OVS_LOG_INFO("No Net Buffer List context"); return; } while (ctx) { OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d", nbl, ctx, ctx->Size, ctx->Offset); ctx = ctx->Next; } }
/* * -------------------------------------------------------------------------- * Implements filter driver's FilterOidRequestComplete function. * -------------------------------------------------------------------------- */ VOID OvsExtOidRequestComplete(NDIS_HANDLE filterModuleContext, PNDIS_OID_REQUEST oidRequest, NDIS_STATUS status) { POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext; PNDIS_OID_REQUEST origReq = OvsOidGetOrigRequest(oidRequest); POVS_OID_CONTEXT oidContext = OvsOidGetContext(oidRequest); /* Only one of the two should be set */ ASSERT(origReq != NULL || oidContext != NULL); ASSERT(oidContext != NULL || origReq != NULL); OVS_LOG_TRACE("Enter: oidRequest %p, reqType: %d", oidRequest, oidRequest->RequestType); if (origReq == NULL) { NdisInterlockedDecrement(&(switchObject->pendingOidCount)); oidContext->status = status; NdisSetEvent(&oidContext->oidComplete); OVS_LOG_INFO("Internally generated request"); goto done; } switch(oidRequest->RequestType) { case NdisRequestMethod: OvsOidRequestCompleteMethod(switchObject, oidRequest, origReq, status); break; case NdisRequestSetInformation: OvsOidRequestCompleteSetInfo(switchObject, oidRequest, origReq, status); break; case NdisRequestQueryInformation: case NdisRequestQueryStatistics: default: OvsOidRequestCompleteQuery(switchObject, oidRequest, origReq, status); break; } OvsOidSetOrigRequest(oidRequest, NULL); NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, oidRequest); NdisFOidRequestComplete(switchObject->NdisFilterHandle, origReq, status); NdisInterlockedDecrement(&(switchObject->pendingOidCount)); done: OVS_LOG_TRACE("Exit"); }
static VOID OvsDumpMDLChain(PMDL mdl) { PMDL tmp; tmp = mdl; while (tmp) { OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p" " ByteCount: %d, ByteOffset: %d", tmp, tmp->Size, tmp->MappedSystemVa, tmp->StartVa, tmp->ByteCount, tmp->ByteOffset); tmp = tmp->Next; } }
/* * -------------------------------------------------------------------------- * OvsFullCopyToMultipleNBLs -- * * Copy NBL to multiple NBLs, each NB will have its own NBL * -------------------------------------------------------------------------- */ PNET_BUFFER_LIST OvsFullCopyToMultipleNBLs(PVOID ovsContext, PNET_BUFFER_LIST nbl, UINT32 headRoom, BOOLEAN copyNblInfo) { POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; PNET_BUFFER_LIST firstNbl, currNbl, newNbl; PNET_BUFFER nb; POVS_BUFFER_CONTEXT srcCtx; 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); newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo); if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) { return newNbl; } else { firstNbl = newNbl; currNbl = newNbl; } while (nb) { newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo); if (newNbl == NULL) { goto copymultiple_error; } NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl; currNbl = newNbl; nb = NET_BUFFER_NEXT_NB(nb); } return firstNbl; copymultiple_error: while (firstNbl) { currNbl = firstNbl; firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl); NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL; OvsCompleteNBL(context, currNbl, TRUE); } return NULL; }
static VOID OvsDumpNetBuffer(PNET_BUFFER nb) { OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p " "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d", nb, NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle, NET_BUFFER_FIRST_MDL(nb), NET_BUFFER_CURRENT_MDL(nb), NET_BUFFER_CURRENT_MDL_OFFSET(nb), NET_BUFFER_DATA_LENGTH(nb), NET_BUFFER_DATA_OFFSET(nb)); OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb)); }
static VOID OvsDumpNetBufferList(PNET_BUFFER_LIST nbl) { PNET_BUFFER nb; OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d " "poolHandle: %p", nbl, nbl->ParentNetBufferList, nbl->SourceHandle, nbl->ChildRefCount, nbl->NdisPoolHandle); OvsDumpNBLContext(nbl); nb = NET_BUFFER_LIST_FIRST_NB(nbl); while (nb) { OvsDumpNetBuffer(nb); nb = NET_BUFFER_NEXT_NB(nb); } }
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); }
NDIS_STATUS OvsExtOidRequest(NDIS_HANDLE filterModuleContext, PNDIS_OID_REQUEST oidRequest) { POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext; NDIS_STATUS status = NDIS_STATUS_SUCCESS; PNDIS_OID_REQUEST clonedOidRequest = NULL; struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION); BOOLEAN completeOid = FALSE; ULONG bytesNeeded = 0; OVS_LOG_TRACE("Enter: oidRequest %p, reqType: %d", oidRequest, oidRequest->RequestType); status = NdisAllocateCloneOidRequest(switchObject->NdisFilterHandle, oidRequest, OVS_MEMORY_TAG, &clonedOidRequest); if (status != NDIS_STATUS_SUCCESS) { goto done; } NdisInterlockedIncrement(&(switchObject->pendingOidCount)); /* set the original oid request in cloned one. */ OvsOidSetOrigRequest(clonedOidRequest, oidRequest); OvsOidSetContext(clonedOidRequest, NULL); switch(clonedOidRequest->RequestType) { case NdisRequestSetInformation: status = OvsProcessSetOid(switchObject, clonedOidRequest, &completeOid); break; case NdisRequestMethod: status = OvsProcessMethodOid(switchObject, clonedOidRequest, &completeOid, &bytesNeeded); break; default: /* We do not handle other request types as of now. * We are just a passthrough for those. */ break; } if (completeOid == TRUE) { /* dont leave any reference back to original request, * even if we are freeing it up. */ OVS_LOG_INFO("Complete True oidRequest %p.", oidRequest); OvsOidSetOrigRequest(clonedOidRequest, NULL); NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, clonedOidRequest); methodInfo->BytesNeeded = bytesNeeded; NdisInterlockedDecrement(&switchObject->pendingOidCount); goto done; } /* pass the request down */ status = NdisFOidRequest(switchObject->NdisFilterHandle, clonedOidRequest); if (status != NDIS_STATUS_PENDING) { OvsExtOidRequestComplete(switchObject, clonedOidRequest, status); /* sample code says so */ status = NDIS_STATUS_PENDING; } done: OVS_LOG_TRACE("Exit: status %8x.", status); return status; }
static NDIS_STATUS OvsProcessSetOid(POVS_SWITCH_CONTEXT switchObject, PNDIS_OID_REQUEST oidRequest, PBOOLEAN complete) { NDIS_STATUS status = NDIS_STATUS_SUCCESS; struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION); *complete = FALSE; OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu", oidRequest, setInfo->Oid); /* Verify the basic Oid paramters first */ if (setInfo->InformationBufferLength && (setInfo->InformationBufferLength < sizeof(NDIS_OBJECT_HEADER))) { status = NDIS_STATUS_INVALID_OID; OVS_LOG_INFO("Invalid input %d", setInfo->InformationBufferLength); goto error; } /* Documentation does not specify what should be done * if informationBuffer is not present. Although it mentions the * structure type informationBUffer points to for each oid request, * but it does not explicitly mention that it is a MUST. * hence we are following this scenario same way as what sample code * mentions. */ if (!(setInfo->InformationBufferLength)) { /* We cannot do anything about this oid request, * lets just pass it down. */ OVS_LOG_INFO("Buffer Length Zero"); goto done; } switch(setInfo->Oid) { case OID_SWITCH_PORT_PROPERTY_ADD: case OID_SWITCH_PORT_PROPERTY_UPDATE: case OID_SWITCH_PORT_PROPERTY_DELETE: status = OvsProcessSetOidPortProp(switchObject, oidRequest); break; case OID_SWITCH_PORT_CREATE: case OID_SWITCH_PORT_UPDATED: case OID_SWITCH_PORT_TEARDOWN: case OID_SWITCH_PORT_DELETE: status = OvsProcessSetOidPort(switchObject, oidRequest); break; case OID_SWITCH_NIC_CREATE: case OID_SWITCH_NIC_CONNECT: case OID_SWITCH_NIC_UPDATED: case OID_SWITCH_NIC_DISCONNECT: case OID_SWITCH_NIC_DELETE: status = OvsProcessSetOidNic(switchObject, oidRequest); break; default: /* Non handled OID request */ break; } if (status != NDIS_STATUS_SUCCESS) { goto error; } goto done; error: *complete = TRUE; done: OVS_LOG_TRACE("Exit: status %8x.", status); return status; }
NTSTATUS OvsDeviceControl(PDEVICE_OBJECT deviceObject, PIRP irp) { PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; PFILE_OBJECT fileObject; PVOID inputBuffer; PVOID outputBuffer; UINT32 inputBufferLen, outputBufferLen, mdlBufferLen; UINT32 code, replyLen = 0; #ifdef DBG POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject); ASSERT(deviceObject == gOvsDeviceObject); ASSERT(ovsExt); ASSERT(ovsExt->numberOpenInstance > 0); #else UNREFERENCED_PARAMETER(deviceObject); #endif irpSp = IoGetCurrentIrpStackLocation(irp); ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL); ASSERT(irpSp->FileObject != NULL); fileObject = irpSp->FileObject; code = irpSp->Parameters.DeviceIoControl.IoControlCode; inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength; outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength; /* * In case of an IRP with METHOD_IN_DIRECT or METHOD_OUT_DIRECT, the size * of the MDL is stored in Parameters.DeviceIoControl.OutputBufferLength. */ mdlBufferLen = outputBufferLen; outputBuffer = inputBuffer = irp->AssociatedIrp.SystemBuffer; switch(code) { case OVS_IOCTL_VERSION_GET: status = OvsGetVersionIoctl(outputBuffer, outputBufferLen, &replyLen); break; case OVS_IOCTL_DP_DUMP: status = OvsDpDumpIoctl(outputBuffer, outputBufferLen, &replyLen); break; case OVS_IOCTL_DP_GET: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { status = OvsDpGetIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } break; case OVS_IOCTL_DP_SET: status = STATUS_NOT_IMPLEMENTED; break; case OVS_IOCTL_VPORT_DUMP: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsDumpVportIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } else { status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_VPORT_GET: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsGetVportIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } else { status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_VPORT_SET: status = STATUS_NOT_IMPLEMENTED; break; case OVS_IOCTL_VPORT_ADD: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsAddVportIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } else { status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_VPORT_DEL: status = OvsDelVportIoctl(inputBuffer, inputBufferLen, &replyLen); break; case OVS_IOCTL_VPORT_EXT_INFO: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsGetExtInfoIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } else { OVS_LOG_INFO("ExtInfo: fail to get outputBuffer address"); status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_FLOW_DUMP: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsDumpFlowIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } else { status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_FLOW_GET: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsGetFlowIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } else { status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_FLOW_PUT: // XXX: This is not really working - mapping the input buffer // XXX: inputBufferLen = mdlBufferLen; // inputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, // NormalPagePriority); status = OvsPutFlowIoctl(inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); break; case OVS_IOCTL_FLOW_FLUSH: status = OvsFlushFlowIoctl(inputBuffer, inputBufferLen); break; case OVS_IOCTL_QOS_QUEUE_DUMP: case OVS_IOCTL_QOS_QUEUE_GET: case OVS_IOCTL_QOS_QUEUE_SET: status = STATUS_NOT_IMPLEMENTED; break; case OVS_IOCTL_DATAPATH_SUBSCRIBE: status = OvsSubscribeDpIoctl(fileObject, inputBuffer, inputBufferLen); break; case OVS_IOCTL_DATAPATH_READ: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer) { status = OvsReadDpIoctl(fileObject, outputBuffer, outputBufferLen, &replyLen); } else { status = STATUS_INSUFFICIENT_RESOURCES; } break; case OVS_IOCTL_DATAPATH_OPERATE: status = STATUS_NOT_IMPLEMENTED; break; case OVS_IOCTL_DATAPATH_EXECUTE: // XXX: need to make the input direct status = OvsExecuteDpIoctl(inputBuffer, inputBufferLen, outputBufferLen); break; case OVS_IOCTL_DATAPATH_PURGE: status = OvsPurgeDpIoctl(fileObject); break; case OVS_IOCTL_DATAPATH_WAIT: status = OvsWaitDpIoctl(irp, fileObject); break; case OVS_IOCTL_EVENT_SUBSCRIBE: status = OvsSubscribeEventIoctl(fileObject, inputBuffer, inputBufferLen); break; case OVS_IOCTL_EVENT_POLL: if (irp->MdlAddress == NULL) { status = STATUS_INVALID_PARAMETER; break; } outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); if (outputBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { status = OvsPollEventIoctl(fileObject, inputBuffer, inputBufferLen, outputBuffer, outputBufferLen, &replyLen); } break; case OVS_IOCTL_EVENT_WAIT: status = OvsWaitEventIoctl(irp, fileObject, inputBuffer, inputBufferLen); break; case OVS_IOCTL_DP_TIMESTAMP_SET: if (inputBufferLen != sizeof (ovsUserTimestampDelta)) { status = STATUS_INFO_LENGTH_MISMATCH; } else { int64 currentUserTS = *(int64 *)inputBuffer; LARGE_INTEGER tickCount; /* So many ticks since system booted. */ KeQueryTickCount(&tickCount); ovsUserTimestampDelta = currentUserTS - (tickCount.QuadPart * ovsTimeIncrementPerTick); status = STATUS_SUCCESS; } break; default: status = STATUS_INVALID_DEVICE_REQUEST; break; } if (status == STATUS_PENDING) { return status; } else { /* * When the system-address-space mapping that is returned by * MmGetSystemAddressForMdlSafe is no longer needed, it must be * released. * http://msdn.microsoft.com/en-us/library/windows/hardware/ff554559(v=vs.85).aspx * * We might have to release the MDL here. */ return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, 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; }
/* * -------------------------------------------------------------------------- * OvsPartialCopyNBL -- * * Partial copy NBL, if there is multiple NB in NBL, each one will be * copied. We also reserve headroom for the new NBL. * * Please note, * NBL should have OVS_BUFFER_CONTEXT setup before calling * this function. * The NBL should already have ref to itself so that during copy * it will not be freed. * -------------------------------------------------------------------------- */ PNET_BUFFER_LIST OvsPartialCopyNBL(PVOID ovsContext, PNET_BUFFER_LIST nbl, UINT32 copySize, UINT32 headRoom, BOOLEAN copyNblInfo) { PNET_BUFFER_LIST newNbl; POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; NDIS_STATUS status; PNET_BUFFER srcNb, dstNb; ULONG byteCopied; POVS_NBL_POOL ovsPool = &context->ovsPool; POVS_BUFFER_CONTEXT srcCtx, dstCtx; UINT16 flags; 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; } if (copySize) { NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL); } newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool, NULL, 0); if (copySize) { status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0, NULL, NULL); ASSERT(status == NDIS_STATUS_SUCCESS); } if (newNbl == NULL) { return NULL; } /* * Allocate private memory for copy */ if (copySize + headRoom) { status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom, 0, NULL, NULL); if (status != NDIS_STATUS_SUCCESS) { goto retreat_error; } if (headRoom) { NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL); } if (copySize) { srcNb = NET_BUFFER_LIST_FIRST_NB(nbl); dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl); while (srcNb) { status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize, srcNb, 0, &byteCopied); if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) { goto nbl_context_error; } srcNb = NET_BUFFER_NEXT_NB(srcNb); dstNb = NET_BUFFER_NEXT_NB(dstNb); } } } status = OvsAllocateNBLContext(context, newNbl); if (status != NDIS_STATUS_SUCCESS) { goto nbl_context_error; } status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo); if (status != NDIS_STATUS_SUCCESS) { goto copy_list_info_error; } #ifdef DBG InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount); #endif newNbl->ParentNetBufferList = nbl; dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); ASSERT(dstCtx != NULL); flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER); flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT; srcNb = NET_BUFFER_LIST_FIRST_NB(nbl); OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize, OVS_DEFAULT_PORT_NO); InterlockedIncrement((LONG volatile *)&srcCtx->refCount); #ifdef DBG OvsDumpNetBufferList(nbl); OvsDumpForwardingDetails(nbl); OvsDumpNetBufferList(newNbl); OvsDumpForwardingDetails(newNbl); #endif OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl); return newNbl; copy_list_info_error: OvsFreeNBLContext(context, newNbl); nbl_context_error: if (copySize) { NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL); } retreat_error: NdisFreeCloneNetBufferList(newNbl, 0); return NULL; }
/* * -------------------------------------------------------------------------- * OvsTcpSegmentyNBL -- * * Segment TCP payload, and prepend each segment with ether/IP/TCP header. * Leave headRoom for additional encap. * * Please note, * NBL should have OVS_BUFFER_CONTEXT setup before calling * this function. * The NBL should already have ref to itself so that during copy * it will not be freed. * Currently this API assert there is only one NB in an NBL, it needs * to be fixed if we receive multiple NBs in an NBL. * -------------------------------------------------------------------------- */ PNET_BUFFER_LIST OvsTcpSegmentNBL(PVOID ovsContext, PNET_BUFFER_LIST nbl, POVS_PACKET_HDR_INFO hdrInfo, UINT32 mss, UINT32 headRoom) { POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; #ifdef DBG POVS_NBL_POOL ovsPool = &context->ovsPool; #endif POVS_BUFFER_CONTEXT dstCtx, srcCtx; UINT32 size, hdrSize, seqNumber; PNET_BUFFER_LIST newNbl; PNET_BUFFER nb, newNb; NDIS_STATUS status; UINT16 segmentSize; ULONG copiedSize; 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); ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL); /* Figure out the segment header size */ status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber); if (status != NDIS_STATUS_SUCCESS) { OVS_LOG_INFO("Cannot parse NBL header"); return NULL; } size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize; /* XXX add to ovsPool counters? */ newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize, mss, hdrSize + headRoom , 0, 0); if (newNbl == NULL) { return NULL; } /* Now deal with TCP payload */ for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL; newNb = NET_BUFFER_NEXT_NB(newNb)) { segmentSize = (size > mss ? mss : size) & 0xffff; if (headRoom) { NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL); } /* Now copy the eth/IP/TCP header and fix up */ status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0, &copiedSize); if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) { goto nblcopy_error; } status = FixSegmentHeader(newNb, segmentSize, seqNumber); if (status != NDIS_STATUS_SUCCESS) { goto nblcopy_error; } /* Move on to the next segment */ size -= segmentSize; seqNumber += segmentSize; } status = OvsAllocateNBLContext(context, newNbl); if (status != NDIS_STATUS_SUCCESS) { goto nblcopy_error; } status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE); if (status != NDIS_STATUS_SUCCESS) { goto nbl_context_error; } newNbl->ParentNetBufferList = nbl; /* Remember it's a fragment NBL so we can free it properly */ dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); ASSERT(dstCtx != NULL); dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER; dstCtx->refCount = 1; dstCtx->magic = OVS_CTX_MAGIC; dstCtx->dataOffsetDelta = hdrSize + headRoom; InterlockedIncrement((LONG volatile *)&srcCtx->refCount); #ifdef DBG InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount); OvsDumpNetBufferList(nbl); OvsDumpForwardingDetails(nbl); OvsDumpNetBufferList(newNbl); OvsDumpForwardingDetails(newNbl); #endif OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl); return newNbl; nbl_context_error: OvsFreeNBLContext(context, newNbl); nblcopy_error: #ifdef DBG InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount); #endif NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0); return NULL; }