summaryrefslogtreecommitdiff
path: root/datapath-windows/ovsext/Oid.c
diff options
context:
space:
mode:
authorSamuel Ghinet <sghinet@cloudbasesolutions.com>2014-08-29 04:06:48 +0000
committerBen Pfaff <blp@nicira.com>2014-08-29 07:55:05 -0700
commitfa1324c92810c6b1e33b7e87caaaf2e6c4041040 (patch)
tree8e06f5d991d755215bb6839a997bc58721b2d754 /datapath-windows/ovsext/Oid.c
parentfd972eb87a888242fb1a8ec2394fa7b3030fbd7d (diff)
downloadopenvswitch-fa1324c92810c6b1e33b7e87caaaf2e6c4041040.tar.gz
datapath-windows: Rename files.
This patch includes the file renaming and accommodations needed for the file renaming to build the forwarding extension for Hyper-V. This patch is also a follow-up for the thread: http://openvswitch.org/pipermail/dev/2014-August/044005.html Signed-off-by: Samuel Ghinet <sghinet@cloudbasesolutions.com> Co-authored-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'datapath-windows/ovsext/Oid.c')
-rw-r--r--datapath-windows/ovsext/Oid.c854
1 files changed, 854 insertions, 0 deletions
diff --git a/datapath-windows/ovsext/Oid.c b/datapath-windows/ovsext/Oid.c
new file mode 100644
index 000000000..a67534714
--- /dev/null
+++ b/datapath-windows/ovsext/Oid.c
@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) 2014 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "precomp.h"
+#include "Switch.h"
+#include "Vport.h"
+#include "NetProto.h"
+#include "User.h"
+#include "Flow.h"
+#include "Event.h"
+#include "User.h"
+#include "Oid.h"
+
+/* Due to an imported header file */
+#pragma warning( disable:4505 )
+
+#ifdef OVS_DBG_MOD
+#undef OVS_DBG_MOD
+#endif
+#define OVS_DBG_MOD OVS_DBG_DISPATCH
+#include "Debug.h"
+
+typedef struct _OVS_OID_CONTEXT {
+ NDIS_EVENT oidComplete;
+ NDIS_STATUS status;
+} OVS_OID_CONTEXT, *POVS_OID_CONTEXT;
+
+
+VOID
+OvsExtOidRequestComplete(NDIS_HANDLE filterModuleContext,
+ PNDIS_OID_REQUEST oidRequest,
+ NDIS_STATUS status);
+static VOID
+OvsOidRequestCompleteMethod(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest,
+ PNDIS_OID_REQUEST origOidRequest,
+ NDIS_STATUS status);
+static VOID
+OvsOidRequestCompleteSetInfo(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest,
+ PNDIS_OID_REQUEST origOidRequest,
+ NDIS_STATUS status);
+static VOID
+OvsOidRequestCompleteQuery(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest,
+ PNDIS_OID_REQUEST origOidRequest,
+ NDIS_STATUS status);
+
+static NDIS_STATUS
+OvsProcessSetOidPortProp(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest);
+static NDIS_STATUS
+OvsProcessSetOidPort(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest);
+static NDIS_STATUS
+OvsProcessSetOidNic(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest);
+
+__inline BOOLEAN
+OvsCheckOidHeaderFunc(PNDIS_OBJECT_HEADER header,
+ LONG propRev,
+ LONG propSize)
+{
+ return header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+ header->Revision < propRev ||
+ header->Size < propSize;
+}
+
+#define OvsCheckOidHeader(_hdr, _rev) \
+ OvsCheckOidHeaderFunc(_hdr, _rev, ##NDIS_SIZEOF_##_rev)
+
+static __inline VOID
+OvsOidSetOrigRequest(PNDIS_OID_REQUEST clonedRequest,
+ PNDIS_OID_REQUEST origRequest)
+{
+ *(PVOID*)(&clonedRequest->SourceReserved[0]) = origRequest;
+}
+
+static __inline PNDIS_OID_REQUEST
+OvsOidGetOrigRequest(PNDIS_OID_REQUEST clonedRequest)
+{
+ return *((PVOID*)(&clonedRequest->SourceReserved[0]));
+}
+
+static __inline VOID
+OvsOidSetContext(PNDIS_OID_REQUEST clonedRequest,
+ POVS_OID_CONTEXT origRequest)
+{
+ *(PVOID*)(&clonedRequest->SourceReserved[8]) = origRequest;
+}
+
+static __inline POVS_OID_CONTEXT
+OvsOidGetContext(PNDIS_OID_REQUEST clonedRequest)
+{
+ return *((PVOID*)(&clonedRequest->SourceReserved[8]));
+}
+
+static NDIS_STATUS
+OvsProcessSetOidPortProp(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest)
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
+ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS portPropParam =
+ setInfo->InformationBuffer;
+ BOOLEAN checkFailed = TRUE;
+
+ UNREFERENCED_PARAMETER(switchObject);
+
+ if (setInfo->Oid == OID_SWITCH_PORT_PROPERTY_DELETE) {
+ checkFailed = OvsCheckOidHeader(
+ (PNDIS_OBJECT_HEADER)portPropParam,
+ NDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS_REVISION_1);
+ } else {
+ /* it must be a add or update request */
+ checkFailed = OvsCheckOidHeader(
+ (PNDIS_OBJECT_HEADER)portPropParam,
+ NDIS_SWITCH_PORT_PROPERTY_PARAMETERS_REVISION_1);
+ }
+
+ if (checkFailed) {
+ status = NDIS_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (portPropParam->PropertyType == NdisSwitchPortPropertyTypeVlan) {
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ goto done;
+ }
+
+done:
+ return status;
+}
+
+static NDIS_STATUS
+OvsProcessSetOidPort(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest)
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
+ PNDIS_SWITCH_PORT_PARAMETERS portParam = setInfo->InformationBuffer;
+
+ if (OvsCheckOidHeader((PNDIS_OBJECT_HEADER)portParam,
+ NDIS_SWITCH_PORT_PARAMETERS_REVISION_1)) {
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ goto done;
+ }
+
+ switch(setInfo->Oid) {
+ case OID_SWITCH_PORT_CREATE:
+ status = OvsCreatePort(switchObject, portParam);
+ break;
+ case OID_SWITCH_PORT_TEARDOWN:
+ OvsTeardownPort(switchObject, portParam);
+ break;
+ case OID_SWITCH_PORT_DELETE:
+ OvsDeletePort(switchObject, portParam);
+ break;
+ default:
+ break;
+ }
+
+done:
+ return status;
+}
+
+static NDIS_STATUS
+OvsProcessSetOidNic(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest)
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
+ PNDIS_SWITCH_NIC_PARAMETERS nicParam = setInfo->InformationBuffer;
+
+ if (OvsCheckOidHeader((PNDIS_OBJECT_HEADER)nicParam,
+ NDIS_SWITCH_NIC_PARAMETERS_REVISION_1)) {
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ goto done;
+ }
+
+ switch(setInfo->Oid) {
+ case OID_SWITCH_NIC_CREATE:
+ status = OvsCreateNic(switchObject, nicParam);
+ break;
+ case OID_SWITCH_NIC_CONNECT:
+ OvsConnectNic(switchObject, nicParam);
+ break;
+ case OID_SWITCH_NIC_UPDATED:
+ OvsUpdateNic(switchObject, nicParam);
+ break;
+ case OID_SWITCH_NIC_DISCONNECT:
+ OvsDisconnectNic(switchObject, nicParam);
+ break;
+ case OID_SWITCH_NIC_DELETE:
+ OvsDeleteNic(switchObject, nicParam);
+ break;
+ default:
+ break;
+ }
+
+done:
+ 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;
+}
+
+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;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * Implements filter driver's FilterOidRequest function.
+ * --------------------------------------------------------------------------
+ */
+
+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;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * 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
+OvsOidRequestCompleteMethod(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest,
+ PNDIS_OID_REQUEST origOidRequest,
+ NDIS_STATUS status)
+{
+ UNREFERENCED_PARAMETER(status);
+ UNREFERENCED_PARAMETER(switchObject);
+
+ struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
+ struct _METHOD *origMethodInfo = &(origOidRequest->DATA.
+ METHOD_INFORMATION);
+
+ OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
+ oidRequest, methodInfo->Oid);
+
+ origMethodInfo->OutputBufferLength = methodInfo->OutputBufferLength;
+ origMethodInfo->BytesRead = methodInfo->BytesRead;
+ origMethodInfo->BytesNeeded = methodInfo->BytesNeeded;
+ origMethodInfo->BytesWritten = methodInfo->BytesWritten;
+
+ OVS_LOG_TRACE("Exit");
+}
+
+static VOID
+OvsOidRequestCompleteSetInfo(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest,
+ PNDIS_OID_REQUEST origOidRequest,
+ NDIS_STATUS status)
+{
+ struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
+ struct _SET *origSetInfo = &(origOidRequest->DATA.SET_INFORMATION);
+ PNDIS_OBJECT_HEADER origHeader = origSetInfo->InformationBuffer;
+
+ OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
+ oidRequest, setInfo->Oid);
+
+ origSetInfo->BytesRead = setInfo->BytesRead;
+ origSetInfo->BytesNeeded = setInfo->BytesNeeded;
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ switch(setInfo->Oid) {
+ case OID_SWITCH_PORT_CREATE:
+ OvsDeletePort(switchObject,
+ (PNDIS_SWITCH_PORT_PARAMETERS)origHeader);
+ break;
+
+ case OID_SWITCH_NIC_CREATE:
+ OvsDeleteNic(switchObject,
+ (PNDIS_SWITCH_NIC_PARAMETERS)origHeader);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ OVS_LOG_TRACE("Exit");
+}
+
+static VOID
+OvsOidRequestCompleteQuery(POVS_SWITCH_CONTEXT switchObject,
+ PNDIS_OID_REQUEST oidRequest,
+ PNDIS_OID_REQUEST origOidRequest,
+ NDIS_STATUS status)
+{
+ UNREFERENCED_PARAMETER(switchObject);
+ UNREFERENCED_PARAMETER(status);
+
+ struct _QUERY *queryInfo = &((oidRequest->DATA).QUERY_INFORMATION);
+ struct _QUERY *origQueryInfo = &((origOidRequest->DATA).QUERY_INFORMATION);
+
+ OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
+ oidRequest, queryInfo->Oid);
+
+ origQueryInfo->BytesWritten = queryInfo->BytesWritten;
+ origQueryInfo->BytesNeeded = queryInfo->BytesNeeded;
+
+ OVS_LOG_TRACE("Exit");
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * Implements filter driver's FilterCancelOidRequest function.
+ * --------------------------------------------------------------------------
+ */
+VOID
+OvsExtCancelOidRequest(NDIS_HANDLE filterModuleContext,
+ PVOID requestId)
+{
+ OVS_LOG_TRACE("Enter: requestId: %p", requestId);
+
+ UNREFERENCED_PARAMETER(filterModuleContext);
+ UNREFERENCED_PARAMETER(requestId);
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * Utility function to issue the specified OID to the NDIS stack. The OID is
+ * directed towards the miniport edge of the extensible switch.
+ * An OID that gets issued may not complete immediately, and in such cases, the
+ * function waits for the OID to complete. Thus, this function must not be
+ * called at the PASSIVE_LEVEL.
+ * --------------------------------------------------------------------------
+ */
+static NDIS_STATUS
+OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext,
+ NDIS_REQUEST_TYPE oidType,
+ UINT32 oidRequestEnum,
+ PVOID oidInputBuffer,
+ UINT32 inputSize,
+ PVOID oidOutputBuffer,
+ UINT32 outputSize,
+ UINT32 *outputSizeNeeded)
+{
+ NDIS_STATUS status;
+ PNDIS_OID_REQUEST oidRequest;
+ POVS_OID_CONTEXT oidContext;
+ ULONG OvsExtOidRequestId = 'ISVO';
+
+ DBG_UNREFERENCED_PARAMETER(inputSize);
+ DBG_UNREFERENCED_PARAMETER(oidInputBuffer);
+
+ OVS_LOG_TRACE("Enter: switchContext: %p, oidType: %d",
+ switchContext, oidType);
+
+ ASSERT(oidInputBuffer == NULL || inputSize != 0);
+ ASSERT(oidOutputBuffer == NULL || outputSize != 0);
+ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ oidRequest = OvsAllocateMemory(sizeof *oidRequest);
+ if (!oidRequest) {
+ status = NDIS_STATUS_RESOURCES;
+ goto done;
+ }
+
+ oidContext = OvsAllocateMemory(sizeof *oidContext);
+ if (!oidContext) {
+ OvsFreeMemory(oidRequest);
+ status = NDIS_STATUS_RESOURCES;
+ goto done;
+ }
+
+ RtlZeroMemory(oidRequest, sizeof *oidRequest);
+ RtlZeroMemory(oidContext, sizeof *oidContext);
+
+ oidRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ oidRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ oidRequest->Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
+
+ oidRequest->RequestType = oidType;
+ oidRequest->PortNumber = 0;
+ oidRequest->Timeout = 0;
+ oidRequest->RequestId = (PVOID)OvsExtOidRequestId;
+
+ switch(oidType) {
+ case NdisRequestQueryInformation:
+ oidRequest->DATA.QUERY_INFORMATION.Oid = oidRequestEnum;
+ oidRequest->DATA.QUERY_INFORMATION.InformationBuffer = oidOutputBuffer;
+ oidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = outputSize;
+ break;
+ default:
+ ASSERT(FALSE);
+ status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /*
+ * We make use of the SourceReserved field in the OID request to store
+ * pointers to the original OID (if any), and also context for completion
+ * (if any).
+ */
+ oidContext->status = NDIS_STATUS_SUCCESS;
+ NdisInitializeEvent(&oidContext->oidComplete);
+
+ OvsOidSetOrigRequest(oidRequest, NULL);
+ OvsOidSetContext(oidRequest, oidContext);
+
+ NdisInterlockedIncrement(&(switchContext->pendingOidCount));
+ status = NdisFOidRequest(switchContext->NdisFilterHandle, oidRequest);
+ if (status == NDIS_STATUS_PENDING) {
+ NdisWaitEvent(&oidContext->oidComplete, 0);
+ } else {
+ NdisInterlockedDecrement(&(switchContext->pendingOidCount));
+ }
+
+ if (status == NDIS_STATUS_INVALID_LENGTH ||
+ oidContext->status == NDIS_STATUS_INVALID_LENGTH) {
+ switch(oidType) {
+ case NdisRequestQueryInformation:
+ *outputSizeNeeded = oidRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+ }
+
+ status = oidContext->status;
+ ASSERT(status != NDIS_STATUS_PENDING);
+
+ OvsFreeMemory(oidRequest);
+ OvsFreeMemory(oidContext);
+
+done:
+ OVS_LOG_TRACE("Exit: status %8x.", status);
+ return status;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * Utility function to query if the extensible switch has completed activation
+ * successfully.
+ * --------------------------------------------------------------------------
+ */
+NDIS_STATUS
+OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext,
+ BOOLEAN *switchActive)
+{
+ NDIS_STATUS status;
+ PNDIS_SWITCH_PARAMETERS switchParams;
+ UINT32 outputSizeNeeded;
+
+ OVS_LOG_TRACE("Enter: switchContext: %p, switchActive: %p",
+ switchContext, switchActive);
+
+ switchParams = OvsAllocateMemory(sizeof *switchParams);
+ if (!switchParams) {
+ status = NDIS_STATUS_RESOURCES;
+ goto done;
+ }
+
+ /*
+ * Even though 'switchParms' is supposed to be populated by the OID, it
+ * needs to be initialized nevertheless. Otherwise, OID returns
+ * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
+ */
+ RtlZeroMemory(switchParams, sizeof *switchParams);
+ switchParams->Header.Revision = NDIS_SWITCH_PARAMETERS_REVISION_1;
+ switchParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ switchParams->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1;
+
+ status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
+ OID_SWITCH_PARAMETERS, NULL, 0,
+ (PVOID)switchParams, sizeof *switchParams,
+ &outputSizeNeeded);
+
+ ASSERT(status != NDIS_STATUS_INVALID_LENGTH);
+ ASSERT(status != NDIS_STATUS_PENDING);
+ if (status == NDIS_STATUS_SUCCESS) {
+ ASSERT(switchParams->Header.Type == NDIS_OBJECT_TYPE_DEFAULT);
+ ASSERT(switchParams->Header.Revision == NDIS_SWITCH_PARAMETERS_REVISION_1);
+ ASSERT(switchParams->Header.Size ==
+ NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1);
+ *switchActive = switchParams->IsActive;
+ }
+
+ OvsFreeMemory(switchParams);
+
+done:
+ OVS_LOG_TRACE("Exit: status %8x, switchActive: %d.",
+ status, *switchActive);
+ return status;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * Utility function to get the array of ports on the extensible switch. Upon
+ * success, the caller needs to free the returned array.
+ * --------------------------------------------------------------------------
+ */
+NDIS_STATUS
+OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
+ PNDIS_SWITCH_PORT_ARRAY *portArrayOut)
+{
+ PNDIS_SWITCH_PORT_ARRAY portArray;
+ UINT32 arraySize = sizeof *portArray;
+ NDIS_STATUS status = NDIS_STATUS_FAILURE;
+
+ OVS_LOG_TRACE("Enter: switchContext: %p, portArray: %p",
+ switchContext, portArrayOut);
+ do {
+ UINT32 reqdArraySize;
+
+ portArray = OvsAllocateMemory(arraySize);
+ if (!portArray) {
+ status = NDIS_STATUS_RESOURCES;
+ goto done;
+ }
+
+ /*
+ * Even though 'portArray' is supposed to be populated by the OID, it
+ * needs to be initialized nevertheless. Otherwise, OID returns
+ * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
+ */
+ RtlZeroMemory(portArray, sizeof *portArray);
+ portArray->Header.Revision = NDIS_SWITCH_PORT_ARRAY_REVISION_1;
+ portArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ portArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PORT_ARRAY_REVISION_1;
+
+ status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
+ OID_SWITCH_PORT_ARRAY, NULL, 0,
+ (PVOID)portArray, arraySize,
+ &reqdArraySize);
+ if (status == NDIS_STATUS_SUCCESS) {
+ *portArrayOut = portArray;
+ break;
+ }
+
+ OvsFreeMemory(portArray);
+ arraySize = reqdArraySize;
+ if (status != NDIS_STATUS_INVALID_LENGTH) {
+ break;
+ }
+ } while(status == NDIS_STATUS_INVALID_LENGTH);
+
+done:
+ OVS_LOG_TRACE("Exit: status %8x.", status);
+ return status;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * Utility function to get the array of nics on the extensible switch. Upon
+ * success, the caller needs to free the returned array.
+ * --------------------------------------------------------------------------
+ */
+NDIS_STATUS
+OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
+ PNDIS_SWITCH_NIC_ARRAY *nicArrayOut)
+{
+ PNDIS_SWITCH_NIC_ARRAY nicArray;
+ UINT32 arraySize = sizeof *nicArray;
+ NDIS_STATUS status = NDIS_STATUS_FAILURE;
+
+ OVS_LOG_TRACE("Enter: switchContext: %p, nicArray: %p",
+ switchContext, nicArrayOut);
+
+ do {
+ UINT32 reqdArraySize;
+
+ nicArray = OvsAllocateMemory(arraySize);
+ if (!nicArray) {
+ status = NDIS_STATUS_RESOURCES;
+ goto done;
+ }
+
+ /*
+ * Even though 'nicArray' is supposed to be populated by the OID, it
+ * needs to be initialized nevertheless. Otherwise, OID returns
+ * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
+ */
+ RtlZeroMemory(nicArray, sizeof *nicArray);
+ nicArray->Header.Revision = NDIS_SWITCH_NIC_ARRAY_REVISION_1;
+ nicArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ nicArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_NIC_ARRAY_REVISION_1;
+
+ status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
+ OID_SWITCH_NIC_ARRAY, NULL, 0,
+ (PVOID)nicArray, arraySize,
+ &reqdArraySize);
+ if (status == NDIS_STATUS_SUCCESS) {
+ *nicArrayOut = nicArray;
+ break;
+ }
+
+ OvsFreeMemory(nicArray);
+ arraySize = reqdArraySize;
+ if (status != NDIS_STATUS_INVALID_LENGTH) {
+ break;
+ }
+ } while(status == NDIS_STATUS_INVALID_LENGTH);
+
+done:
+ OVS_LOG_TRACE("Exit: status %8x.", status);
+ return status;
+}