2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * XXX: OVS_USE_NL_INTERFACE is being used to keep the legacy DPIF interface
19 * alive while we transition over to the netlink based interface.
20 * OVS_USE_NL_INTERFACE = 0 => legacy inteface to use with dpif-windows.c
21 * OVS_USE_NL_INTERFACE = 1 => netlink inteface to use with ported dpif-linux.c
23 #if defined OVS_USE_NL_INTERFACE && OVS_USE_NL_INTERFACE == 1
28 #include "OvsSwitch.h"
32 #include "OvsPacketIO.h"
33 #include "OvsNetProto.h"
40 #define OVS_DBG_MOD OVS_DBG_DATAPATH
43 #define NETLINK_FAMILY_NAME_LEN 48
47 * Netlink messages are grouped by family (aka type), and each family supports
48 * a set of commands, and can be passed both from kernel -> userspace or
49 * vice-versa. To call into the kernel, userspace uses a device operation which
50 * is outside of a netlink message.
52 * Each command results in the invocation of a handler function to implement the
53 * request functionality.
55 * Expectedly, only certain combinations of (device operation, netlink family,
58 * Here, we implement the basic infrastructure to perform validation on the
59 * incoming message, version checking, and also to invoke the corresponding
60 * handler to do the heavy-lifting.
64 * Handler for a given netlink command. Not all the parameters are used by all
67 typedef NTSTATUS (*NetlinkCmdHandler)(PIRP irp, PFILE_OBJECT fileObject,
68 PVOID inputBuffer, UINT32 inputLength,
69 PVOID outputBuffer, UINT32 outputLength,
72 typedef struct _NETLINK_CMD {
74 NetlinkCmdHandler handler;
75 UINT32 supportedDevOp; /* Supported device operations. */
76 } NETLINK_CMD, *PNETLINK_CMD;
78 /* A netlink family is a group of commands. */
79 typedef struct _NETLINK_FAMILY {
84 NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
86 } NETLINK_FAMILY, *PNETLINK_FAMILY;
89 * Device operations to tag netlink commands with. This is a bitmask since it is
90 * possible that a particular command can be invoked via different device
93 #define OVS_READ_DEV_OP (1 << 0)
94 #define OVS_WRITE_DEV_OP (1 << 1)
95 #define OVS_TRANSACTION_DEV_OP (1 << 2)
97 /* Handlers for the various netlink commands. */
98 static NTSTATUS OvsGetPidCmdHandler(PIRP irp, PFILE_OBJECT fileObject,
99 PVOID inputBuffer, UINT32 inputLength,
100 PVOID outputBuffer, UINT32 outputLength,
104 * The various netlink families, along with the supported commands. Most of
105 * these families and commands are part of the openvswitch specification for a
106 * netlink datapath. In addition, each platform can implement a few families
107 * and commands as extensions.
110 /* Netlink control family: this is a Windows specific family. */
111 NETLINK_CMD nlControlFamilyCmdOps[] = {
112 { OVS_CTRL_CMD_WIN_GET_PID, OvsGetPidCmdHandler, OVS_TRANSACTION_DEV_OP, }
115 NETLINK_FAMILY nlControlFamilyOps = {
116 OVS_WIN_CONTROL_FAMILY,
117 OVS_WIN_NL_CTRL_FAMILY_ID,
118 OVS_WIN_CONTROL_VERSION,
119 OVS_WIN_CONTROL_ATTR_MAX,
120 nlControlFamilyCmdOps,
121 ARRAY_SIZE(nlControlFamilyCmdOps)
126 /* Netlink packet family. */
127 /* XXX: Add commands here. */
128 NETLINK_FAMILY nlPacketFamilyOps = {
130 OVS_WIN_NL_PACKET_FAMILY_ID,
133 NULL, /* XXX: placeholder. */
137 /* Netlink datapath family. */
138 /* XXX: Add commands here. */
139 NETLINK_FAMILY nlDatapathFamilyOps = {
141 OVS_WIN_NL_DATAPATH_FAMILY_ID,
142 OVS_DATAPATH_VERSION,
144 NULL, /* XXX: placeholder. */
148 /* Netlink vport family. */
149 /* XXX: Add commands here. */
150 NETLINK_FAMILY nlVportFamilyOps = {
152 OVS_WIN_NL_VPORT_FAMILY_ID,
155 NULL, /* XXX: placeholder. */
159 /* Netlink flow family. */
160 /* XXX: Add commands here. */
161 NETLINK_FAMILY nlFLowFamilyOps = {
163 OVS_WIN_NL_FLOW_FAMILY_ID,
166 NULL, /* XXX: placeholder. */
171 MapIrpOutputBuffer(PIRP irp,
173 UINT32 requiredLength,
176 ValidateNetlinkCmd(UINT32 devOp,
178 NETLINK_FAMILY *nlFamilyOps);
180 InvokeNetlinkCmdHandler(PIRP irp,
181 PFILE_OBJECT fileObject,
184 NETLINK_FAMILY *nlFamily,
192 /* Handles to the device object for communication with userspace. */
193 NDIS_HANDLE gOvsDeviceHandle;
194 PDEVICE_OBJECT gOvsDeviceObject;
196 _Dispatch_type_(IRP_MJ_CREATE)
197 _Dispatch_type_(IRP_MJ_CLOSE)
198 DRIVER_DISPATCH OvsOpenCloseDevice;
200 _Dispatch_type_(IRP_MJ_CLEANUP)
201 DRIVER_DISPATCH OvsCleanupDevice;
203 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
204 DRIVER_DISPATCH OvsDeviceControl;
207 #pragma alloc_text(INIT, OvsCreateDeviceObject)
208 #pragma alloc_text(PAGE, OvsOpenCloseDevice)
209 #pragma alloc_text(PAGE, OvsCleanupDevice)
210 #pragma alloc_text(PAGE, OvsDeviceControl)
211 #endif // ALLOC_PRAGMA
214 * We might hit this limit easily since userspace opens a netlink descriptor for
215 * each thread, and at least one descriptor per vport. Revisit this later.
217 #define OVS_MAX_OPEN_INSTANCES 512
219 POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
220 UINT32 ovsNumberOfOpenInstances;
221 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
223 NDIS_SPIN_LOCK ovsCtrlLockObj;
224 PNDIS_SPIN_LOCK gOvsCtrlLock;
230 gOvsCtrlLock = &ovsCtrlLockObj;
231 NdisAllocateSpinLock(gOvsCtrlLock);
239 OvsCleanupEventQueue();
241 NdisFreeSpinLock(gOvsCtrlLock);
250 NdisAcquireSpinLock(gOvsCtrlLock);
256 NdisReleaseSpinLock(gOvsCtrlLock);
261 * --------------------------------------------------------------------------
262 * Creates the communication device between user and kernel, and also
263 * initializes the data associated data structures.
264 * --------------------------------------------------------------------------
267 OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
269 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
270 UNICODE_STRING deviceName;
271 UNICODE_STRING symbolicDeviceName;
272 PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
273 NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes;
274 OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle);
276 RtlZeroMemory(dispatchTable,
277 (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH));
278 dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice;
279 dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice;
280 dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice;
281 dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl;
283 NdisInitUnicodeString(&deviceName, OVS_DEVICE_NAME_NT);
284 NdisInitUnicodeString(&symbolicDeviceName, OVS_DEVICE_NAME_DOS);
286 RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
288 OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header,
289 NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
290 NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
291 sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
293 deviceAttributes.DeviceName = &deviceName;
294 deviceAttributes.SymbolicName = &symbolicDeviceName;
295 deviceAttributes.MajorFunctions = dispatchTable;
296 deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION);
298 status = NdisRegisterDeviceEx(ovsExtDriverHandle,
302 if (status != NDIS_STATUS_SUCCESS) {
303 POVS_DEVICE_EXTENSION ovsExt =
304 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(gOvsDeviceObject);
305 ASSERT(gOvsDeviceObject != NULL);
306 ASSERT(gOvsDeviceHandle != NULL);
309 ovsExt->numberOpenInstance = 0;
312 /* Initialize the associated data structures. */
315 OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
321 OvsDeleteDeviceObject()
323 if (gOvsDeviceHandle) {
325 POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)
326 NdisGetDeviceReservedExtension(gOvsDeviceObject);
328 ASSERT(ovsExt->numberOpenInstance == 0);
332 ASSERT(gOvsDeviceObject);
333 NdisDeregisterDeviceEx(gOvsDeviceHandle);
334 gOvsDeviceHandle = NULL;
335 gOvsDeviceObject = NULL;
341 OvsGetOpenInstance(PFILE_OBJECT fileObject,
344 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
346 ASSERT(instance->fileObject == fileObject);
347 if (gOvsSwitchContext == NULL ||
348 gOvsSwitchContext->dpNo != dpNo) {
356 OvsFindOpenInstance(PFILE_OBJECT fileObject)
359 for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES &&
360 j < ovsNumberOfOpenInstances; i++) {
361 if (ovsOpenInstanceArray[i]) {
362 if (ovsOpenInstanceArray[i]->fileObject == fileObject) {
363 return ovsOpenInstanceArray[i];
372 OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
373 PFILE_OBJECT fileObject)
375 POVS_OPEN_INSTANCE instance =
376 (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE));
379 if (instance == NULL) {
380 return STATUS_NO_MEMORY;
382 OvsAcquireCtrlLock();
383 ASSERT(OvsFindOpenInstance(fileObject) == NULL);
385 if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
386 OvsReleaseCtrlLock();
387 OvsFreeMemory(instance);
388 return STATUS_INSUFFICIENT_RESOURCES;
390 RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
392 for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) {
393 if (ovsOpenInstanceArray[i] == NULL) {
394 ovsOpenInstanceArray[i] = instance;
395 instance->cookie = i;
399 ASSERT(i < OVS_MAX_OPEN_INSTANCES);
400 instance->fileObject = fileObject;
401 ASSERT(fileObject->FsContext == NULL);
402 instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
403 if (instance->pid == 0) {
404 /* XXX: check for rollover. */
406 fileObject->FsContext = instance;
407 OvsReleaseCtrlLock();
408 return STATUS_SUCCESS;
412 OvsCleanupOpenInstance(PFILE_OBJECT fileObject)
414 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
416 ASSERT(fileObject == instance->fileObject);
417 OvsCleanupEvent(instance);
418 OvsCleanupPacketQueue(instance);
422 OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
424 POVS_OPEN_INSTANCE instance;
425 ASSERT(fileObject->FsContext);
426 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
427 ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES);
429 OvsAcquireCtrlLock();
430 fileObject->FsContext = NULL;
431 ASSERT(ovsOpenInstanceArray[instance->cookie] == instance);
432 ovsOpenInstanceArray[instance->cookie] = NULL;
433 OvsReleaseCtrlLock();
434 ASSERT(instance->eventQueue == NULL);
435 ASSERT (instance->packetQueue == NULL);
436 OvsFreeMemory(instance);
440 OvsCompleteIrpRequest(PIRP irp,
444 irp->IoStatus.Information = infoPtr;
445 irp->IoStatus.Status = status;
446 IoCompleteRequest(irp, IO_NO_INCREMENT);
452 OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject,
455 PIO_STACK_LOCATION irpSp;
456 NTSTATUS status = STATUS_SUCCESS;
457 PFILE_OBJECT fileObject;
458 POVS_DEVICE_EXTENSION ovsExt =
459 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
461 ASSERT(deviceObject == gOvsDeviceObject);
462 ASSERT(ovsExt != NULL);
464 irpSp = IoGetCurrentIrpStackLocation(irp);
465 fileObject = irpSp->FileObject;
466 OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u",
467 deviceObject, fileObject,
468 ovsExt->numberOpenInstance);
470 switch (irpSp->MajorFunction) {
472 status = OvsAddOpenInstance(ovsExt, fileObject);
473 if (STATUS_SUCCESS == status) {
474 InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance);
478 ASSERT(ovsExt->numberOpenInstance > 0);
479 OvsRemoveOpenInstance(fileObject);
480 InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance);
485 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
488 _Use_decl_annotations_
490 OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
494 PIO_STACK_LOCATION irpSp;
495 PFILE_OBJECT fileObject;
497 NTSTATUS status = STATUS_SUCCESS;
499 POVS_DEVICE_EXTENSION ovsExt =
500 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
502 ASSERT(ovsExt->numberOpenInstance > 0);
505 UNREFERENCED_PARAMETER(deviceObject);
507 ASSERT(deviceObject == gOvsDeviceObject);
508 irpSp = IoGetCurrentIrpStackLocation(irp);
509 fileObject = irpSp->FileObject;
511 ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP);
513 OvsCleanupOpenInstance(fileObject);
515 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
520 * --------------------------------------------------------------------------
521 * IOCTL function handler for the device.
522 * --------------------------------------------------------------------------
525 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
529 PIO_STACK_LOCATION irpSp;
530 NTSTATUS status = STATUS_SUCCESS;
531 PFILE_OBJECT fileObject;
533 PVOID outputBuffer = NULL;
534 UINT32 inputBufferLen, outputBufferLen;
535 UINT32 code, replyLen = 0;
536 POVS_OPEN_INSTANCE instance;
538 OVS_MESSAGE ovsMsgReadOp;
540 NETLINK_FAMILY *nlFamilyOps;
543 POVS_DEVICE_EXTENSION ovsExt =
544 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
545 ASSERT(deviceObject == gOvsDeviceObject);
547 ASSERT(ovsExt->numberOpenInstance > 0);
549 UNREFERENCED_PARAMETER(deviceObject);
552 irpSp = IoGetCurrentIrpStackLocation(irp);
554 ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
555 ASSERT(irpSp->FileObject != NULL);
557 fileObject = irpSp->FileObject;
558 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
559 code = irpSp->Parameters.DeviceIoControl.IoControlCode;
560 inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
561 outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
562 inputBuffer = irp->AssociatedIrp.SystemBuffer;
564 /* Concurrent netlink operations are not supported. */
565 if (InterlockedCompareExchange((LONG volatile *)&instance->inUse, 1, 0)) {
566 status = STATUS_RESOURCE_IN_USE;
571 * Validate the input/output buffer arguments depending on the type of the
575 case OVS_IOCTL_TRANSACT:
576 /* Input buffer is mandatory, output buffer is optional. */
577 if (outputBufferLen != 0) {
578 status = MapIrpOutputBuffer(irp, outputBufferLen,
579 sizeof *ovsMsg, &outputBuffer);
580 if (status != STATUS_SUCCESS) {
583 ASSERT(outputBuffer);
586 if (inputBufferLen < sizeof (*ovsMsg)) {
587 status = STATUS_NDIS_INVALID_LENGTH;
591 ovsMsg = inputBuffer;
592 devOp = OVS_TRANSACTION_DEV_OP;
596 /* Output buffer is mandatory. */
597 if (outputBufferLen != 0) {
598 status = MapIrpOutputBuffer(irp, outputBufferLen,
599 sizeof *ovsMsg, &outputBuffer);
600 if (status != STATUS_SUCCESS) {
603 ASSERT(outputBuffer);
605 status = STATUS_NDIS_INVALID_LENGTH;
610 * Operate in the mode that read ioctl is similar to ReadFile(). This
611 * might change as the userspace code gets implemented.
615 /* Create an NL message for consumption. */
616 ovsMsg = &ovsMsgReadOp;
617 devOp = OVS_READ_DEV_OP;
620 * For implementing read (ioctl or otherwise), we need to store some
621 * state in the instance to indicate the previous command. The state can
622 * setup 'ovsMsgReadOp' appropriately.
624 * XXX: Support for that will be added as the userspace code evolves.
626 status = STATUS_NOT_IMPLEMENTED;
631 case OVS_IOCTL_WRITE:
632 /* Input buffer is mandatory. */
633 if (inputBufferLen < sizeof (*ovsMsg)) {
634 status = STATUS_NDIS_INVALID_LENGTH;
638 ovsMsg = inputBuffer;
639 devOp = OVS_WRITE_DEV_OP;
643 status = STATUS_INVALID_DEVICE_REQUEST;
648 switch (ovsMsg->nlMsg.nlmsg_type) {
649 case OVS_WIN_NL_CTRL_FAMILY_ID:
650 nlFamilyOps = &nlControlFamilyOps;
652 case OVS_WIN_NL_PACKET_FAMILY_ID:
653 case OVS_WIN_NL_DATAPATH_FAMILY_ID:
654 case OVS_WIN_NL_FLOW_FAMILY_ID:
655 case OVS_WIN_NL_VPORT_FAMILY_ID:
656 status = STATUS_NOT_IMPLEMENTED;
660 status = STATUS_INVALID_PARAMETER;
665 * For read operation, the netlink command has already been validated
668 if (devOp != OVS_READ_DEV_OP) {
669 status = ValidateNetlinkCmd(devOp, ovsMsg, nlFamilyOps);
670 if (status != STATUS_SUCCESS) {
675 status = InvokeNetlinkCmdHandler(irp, fileObject, devOp,
677 inputBuffer, inputBufferLen,
678 outputBuffer, outputBufferLen,
684 return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
689 * --------------------------------------------------------------------------
690 * Function to validate a netlink command. Only certain combinations of
691 * (device operation, netlink family, command) are valid.
692 * --------------------------------------------------------------------------
695 ValidateNetlinkCmd(UINT32 devOp,
697 NETLINK_FAMILY *nlFamilyOps)
699 NTSTATUS status = STATUS_INVALID_PARAMETER;
702 for (i = 0; i < nlFamilyOps->opsCount; i++) {
703 if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
704 /* Validate if the command is valid for the device operation. */
705 if ((devOp & nlFamilyOps->cmds[i].supportedDevOp) == 0) {
706 status = STATUS_INVALID_PARAMETER;
710 /* Validate the version. */
711 if (nlFamilyOps->version > ovsMsg->genlMsg.version) {
712 status = STATUS_INVALID_PARAMETER;
716 /* Validate the DP for commands where the DP is actually set. */
717 if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) {
718 OvsAcquireCtrlLock();
719 if (ovsMsg->ovsHdr.dp_ifindex == (INT)gOvsSwitchContext->dpNo) {
720 status = STATUS_INVALID_PARAMETER;
721 OvsReleaseCtrlLock();
724 OvsReleaseCtrlLock();
727 status = STATUS_SUCCESS;
737 * --------------------------------------------------------------------------
738 * Function to invoke the netlink command handler.
739 * --------------------------------------------------------------------------
742 InvokeNetlinkCmdHandler(PIRP irp,
743 PFILE_OBJECT fileObject,
746 NETLINK_FAMILY *nlFamilyOps,
753 NTSTATUS status = STATUS_INVALID_PARAMETER;
756 UNREFERENCED_PARAMETER(devOp);
758 for (i = 0; i < nlFamilyOps->opsCount; i++) {
759 if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
760 status = nlFamilyOps->cmds[i].handler(irp, fileObject,
761 inputBuffer, inputLength,
762 outputBuffer, outputLength,
773 * --------------------------------------------------------------------------
774 * Each handle on the device is assigned a unique PID when the handle is
775 * created. On platforms that support netlink natively, the PID is available
776 * to userspace when the netlink socket is created. However, without native
777 * netlink support on Windows, OVS datapath generates the PID and lets the
778 * userspace query it.
780 * This function implements the query.
781 * --------------------------------------------------------------------------
784 OvsGetPidCmdHandler(PIRP irp,
785 PFILE_OBJECT fileObject,
792 UNREFERENCED_PARAMETER(irp);
793 UNREFERENCED_PARAMETER(fileObject);
794 UNREFERENCED_PARAMETER(inputBuffer);
795 UNREFERENCED_PARAMETER(inputLength);
797 POVS_MESSAGE msgIn = (POVS_MESSAGE)inputBuffer;
798 POVS_MESSAGE msgOut = (POVS_MESSAGE)outputBuffer;
800 if (outputLength >= sizeof *msgOut) {
801 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
803 RtlZeroMemory(msgOut, sizeof *msgOut);
804 msgOut->nlMsg.nlmsg_seq = msgIn->nlMsg.nlmsg_seq;
805 msgOut->nlMsg.nlmsg_pid = instance->pid;
806 *replyLen = sizeof *msgOut;
807 /* XXX: We might need to return the DP index as well. */
809 return STATUS_NDIS_INVALID_LENGTH;
812 return NDIS_STATUS_SUCCESS;
817 * --------------------------------------------------------------------------
818 * Utility function to map the output buffer in an IRP. The buffer is assumed
819 * to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
820 * --------------------------------------------------------------------------
823 MapIrpOutputBuffer(PIRP irp,
825 UINT32 requiredLength,
830 ASSERT(bufferLength);
831 ASSERT(requiredLength);
832 if (!buffer || !irp || bufferLength == 0 || requiredLength == 0) {
833 return STATUS_INVALID_PARAMETER;
836 if (bufferLength < requiredLength) {
837 return STATUS_NDIS_INVALID_LENGTH;
839 if (irp->MdlAddress == NULL) {
840 return STATUS_INVALID_PARAMETER;
842 *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
844 if (*buffer == NULL) {
845 return STATUS_INSUFFICIENT_RESOURCES;
848 return STATUS_SUCCESS;
851 #endif /* OVS_USE_NL_INTERFACE */