/* A netlink family is a group of commands. */
typedef struct _NETLINK_FAMILY {
CHAR *name;
- UINT32 id;
+ UINT16 id;
UINT8 version;
- UINT8 pad;
+ UINT8 pad1;
UINT16 maxAttr;
+ UINT16 pad2;
NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
UINT16 opsCount;
} NETLINK_FAMILY, *PNETLINK_FAMILY;
},
{ .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
.handler = OvsReadEventCmdHandler,
- .supportedDevOp = OVS_READ_EVENT_DEV_OP,
+ .supportedDevOp = OVS_READ_DEV_OP,
.validateDpIndex = FALSE,
},
{ .cmd = OVS_CTRL_CMD_READ_NOTIFY,
.handler = OvsReadPacketCmdHandler,
- .supportedDevOp = OVS_READ_PACKET_DEV_OP,
+ .supportedDevOp = OVS_READ_DEV_OP,
.validateDpIndex = FALSE,
}
};
OvsReleaseCtrlLock();
ASSERT(instance->eventQueue == NULL);
ASSERT (instance->packetQueue == NULL);
+ FreeUserDumpState(instance);
OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
}
return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
}
-
/*
* --------------------------------------------------------------------------
* IOCTL function handler for the device.
goto exit;
}
- /* Concurrent netlink operations are not supported. */
- if (InterlockedCompareExchange((LONG volatile *)&instance->inUse, 1, 0)) {
- status = STATUS_RESOURCE_IN_USE;
- goto done;
- }
-
/*
* Validate the input/output buffer arguments depending on the type of the
* operation.
inputBufferLen = 0;
ovsMsg = &ovsMsgReadOp;
- ovsMsg->nlMsg.nlmsgType = OVS_WIN_NL_CTRL_FAMILY_ID;
+ RtlZeroMemory(ovsMsg, sizeof *ovsMsg);
+ ovsMsg->nlMsg.nlmsgLen = sizeof *ovsMsg;
+ ovsMsg->nlMsg.nlmsgType = nlControlFamilyOps.id;
ovsMsg->nlMsg.nlmsgPid = instance->pid;
+
/* An "artificial" command so we can use NL family function table*/
ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
OVS_CTRL_CMD_EVENT_NOTIFY :
OVS_CTRL_CMD_READ_NOTIFY;
+ ovsMsg->genlMsg.version = nlControlFamilyOps.version;
+
devOp = OVS_READ_DEV_OP;
break;
}
/*
- * For read operation, the netlink command has already been validated
- * previously.
+ * For read operation, avoid duplicate validation since 'ovsMsg' is either
+ * "artificial" or was copied from a previously validated 'ovsMsg'.
*/
if (devOp != OVS_READ_DEV_OP) {
status = ValidateNetlinkCmd(devOp, instance, ovsMsg, nlFamilyOps);
OvsReleaseSwitchContext(gOvsSwitchContext);
exit:
- KeMemoryBarrier();
- instance->inUse = 0;
-
- /* Should not complete a pending IRP unless proceesing is completed */
+ /* Should not complete a pending IRP unless proceesing is completed. */
if (status == STATUS_PENDING) {
+ /* STATUS_PENDING is returned by the NL handler when the request is
+ * to be processed later, so we mark the IRP as pending and complete
+ * it in another thread when the request is processed. */
+ IoMarkIrpPending(irp);
return status;
}
return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
/*
* --------------------------------------------------------------------------
- * Function to invoke the netlink command handler.
+ * Function to invoke the netlink command handler. The function also stores
+ * the return value of the handler function to construct a 'NL_ERROR' message,
+ * and in turn returns success to the caller.
* --------------------------------------------------------------------------
*/
static NTSTATUS
}
}
+ /*
+ * Netlink socket semantics dictate that the return value of the netlink
+ * function should be an error ONLY under fatal conditions. If the message
+ * made it all the way to the handler function, it is not a fatal condition.
+ * Absorb the error returned by the handler function into a 'struct
+ * NL_ERROR' and populate the 'output buffer' to return to userspace.
+ *
+ * This behavior is obviously applicable only to netlink commands that
+ * specify an 'output buffer'. For other commands, we return the error as
+ * is.
+ *
+ * 'STATUS_PENDING' is a special return value and userspace is equipped to
+ * handle it.
+ */
+ if (status != STATUS_SUCCESS && status != STATUS_PENDING) {
+ if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP && *replyLen == 0) {
+ NL_ERROR nlError = NlMapStatusToNlErr(status);
+ POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
+ POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
+ usrParamsCtx->outputBuffer;
+
+ ASSERT(msgError);
+ NlBuildErrorMsg(msgIn, msgError, nlError);
+ *replyLen = msgError->nlMsg.nlmsgLen;
+ }
+
+ if (*replyLen != 0) {
+ status = STATUS_SUCCESS;
+ }
+ }
+
+#ifdef DBG
+ if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP) {
+ ASSERT(status == STATUS_PENDING || *replyLen != 0 || status == STATUS_SUCCESS);
+ }
+#endif
+
return status;
}