datapath-windows: Add packet miss read Netlink command.
[cascardo/ovs.git] / datapath-windows / ovsext / Datapath.c
1 /*
2  * Copyright (c) 2014 VMware, Inc.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
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
22  */
23 #if defined OVS_USE_NL_INTERFACE && OVS_USE_NL_INTERFACE == 1
24
25 #include "precomp.h"
26 #include "Datapath.h"
27 #include "Jhash.h"
28 #include "Switch.h"
29 #include "Vport.h"
30 #include "Event.h"
31 #include "User.h"
32 #include "PacketIO.h"
33 #include "NetProto.h"
34 #include "Flow.h"
35 #include "User.h"
36 #include "Vxlan.h"
37
38 #ifdef OVS_DBG_MOD
39 #undef OVS_DBG_MOD
40 #endif
41 #define OVS_DBG_MOD OVS_DBG_DATAPATH
42 #include "Debug.h"
43
44 #define NETLINK_FAMILY_NAME_LEN 48
45
46
47 /*
48  * Netlink messages are grouped by family (aka type), and each family supports
49  * a set of commands, and can be passed both from kernel -> userspace or
50  * vice-versa. To call into the kernel, userspace uses a device operation which
51  * is outside of a netlink message.
52  *
53  * Each command results in the invocation of a handler function to implement the
54  * request functionality.
55  *
56  * Expectedly, only certain combinations of (device operation, netlink family,
57  * command) are valid.
58  *
59  * Here, we implement the basic infrastructure to perform validation on the
60  * incoming message, version checking, and also to invoke the corresponding
61  * handler to do the heavy-lifting.
62  */
63
64 /*
65  * Handler for a given netlink command. Not all the parameters are used by all
66  * the handlers.
67  */
68 typedef NTSTATUS(NetlinkCmdHandler)(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
69                                     UINT32 *replyLen);
70
71 typedef struct _NETLINK_CMD {
72     UINT16 cmd;
73     NetlinkCmdHandler *handler;
74     UINT32 supportedDevOp;      /* Supported device operations. */
75     BOOLEAN validateDpIndex;    /* Does command require a valid DP argument. */
76 } NETLINK_CMD, *PNETLINK_CMD;
77
78 /* A netlink family is a group of commands. */
79 typedef struct _NETLINK_FAMILY {
80     CHAR *name;
81     UINT32 id;
82     UINT8 version;
83     UINT8 pad;
84     UINT16 maxAttr;
85     NETLINK_CMD *cmds;          /* Array of netlink commands and handlers. */
86     UINT16 opsCount;
87 } NETLINK_FAMILY, *PNETLINK_FAMILY;
88
89 /* Handlers for the various netlink commands. */
90 static NetlinkCmdHandler OvsGetPidCmdHandler,
91                          OvsPendEventCmdHandler,
92                          OvsSubscribeEventCmdHandler,
93                          OvsReadEventCmdHandler,
94                          OvsReadPacketCmdHandler,
95                          OvsNewDpCmdHandler,
96                          OvsGetDpCmdHandler,
97                          OvsSetDpCmdHandler,
98                          OvsGetVportCmdHandler,
99                          OvsSetVportCmdHandler,
100                          OvsNewVportCmdHandler,
101                          OvsDeleteVportCmdHandler;
102
103 NetlinkCmdHandler        OvsGetNetdevCmdHandler;
104
105 static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
106                                        UINT32 *replyLen);
107 static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
108                                 UINT32 *replyLen);
109 static NTSTATUS HandleDpTransactionCommon(
110                     POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen);
111
112 /*
113  * The various netlink families, along with the supported commands. Most of
114  * these families and commands are part of the openvswitch specification for a
115  * netlink datapath. In addition, each platform can implement a few families
116  * and commands as extensions.
117  */
118
119 /* Netlink control family: this is a Windows specific family. */
120 NETLINK_CMD nlControlFamilyCmdOps[] = {
121     { .cmd             = OVS_CTRL_CMD_WIN_GET_PID,
122       .handler         = OvsGetPidCmdHandler,
123       .supportedDevOp  = OVS_TRANSACTION_DEV_OP,
124       .validateDpIndex = FALSE,
125     },
126     { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
127       .handler = OvsPendEventCmdHandler,
128       .supportedDevOp = OVS_WRITE_DEV_OP,
129       .validateDpIndex = TRUE,
130     },
131     { .cmd = OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
132       .handler = OvsSubscribeEventCmdHandler,
133       .supportedDevOp = OVS_WRITE_DEV_OP,
134       .validateDpIndex = TRUE,
135     },
136     { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
137       .handler = OvsReadEventCmdHandler,
138       .supportedDevOp = OVS_READ_EVENT_DEV_OP,
139       .validateDpIndex = FALSE,
140     },
141     { .cmd = OVS_CTRL_CMD_READ_NOTIFY,
142       .handler = OvsReadPacketCmdHandler,
143       .supportedDevOp = OVS_READ_PACKET_DEV_OP,
144       .validateDpIndex = FALSE,
145     }
146 };
147
148 NETLINK_FAMILY nlControlFamilyOps = {
149     .name     = OVS_WIN_CONTROL_FAMILY,
150     .id       = OVS_WIN_NL_CTRL_FAMILY_ID,
151     .version  = OVS_WIN_CONTROL_VERSION,
152     .maxAttr  = OVS_WIN_CONTROL_ATTR_MAX,
153     .cmds     = nlControlFamilyCmdOps,
154     .opsCount = ARRAY_SIZE(nlControlFamilyCmdOps)
155 };
156
157 /* Netlink datapath family. */
158 NETLINK_CMD nlDatapathFamilyCmdOps[] = {
159     { .cmd             = OVS_DP_CMD_NEW,
160       .handler         = OvsNewDpCmdHandler,
161       .supportedDevOp  = OVS_TRANSACTION_DEV_OP,
162       .validateDpIndex = FALSE
163     },
164     { .cmd             = OVS_DP_CMD_GET,
165       .handler         = OvsGetDpCmdHandler,
166       .supportedDevOp  = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
167                          OVS_TRANSACTION_DEV_OP,
168       .validateDpIndex = FALSE
169     },
170     { .cmd             = OVS_DP_CMD_SET,
171       .handler         = OvsSetDpCmdHandler,
172       .supportedDevOp  = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
173                          OVS_TRANSACTION_DEV_OP,
174       .validateDpIndex = TRUE
175     }
176 };
177
178 NETLINK_FAMILY nlDatapathFamilyOps = {
179     .name     = OVS_DATAPATH_FAMILY,
180     .id       = OVS_WIN_NL_DATAPATH_FAMILY_ID,
181     .version  = OVS_DATAPATH_VERSION,
182     .maxAttr  = OVS_DP_ATTR_MAX,
183     .cmds     = nlDatapathFamilyCmdOps,
184     .opsCount = ARRAY_SIZE(nlDatapathFamilyCmdOps)
185 };
186
187 /* Netlink packet family. */
188
189 NETLINK_CMD nlPacketFamilyCmdOps[] = {
190     { .cmd             = OVS_PACKET_CMD_EXECUTE,
191       .handler         = OvsNlExecuteCmdHandler,
192       .supportedDevOp  = OVS_TRANSACTION_DEV_OP,
193       .validateDpIndex = TRUE
194     }
195 };
196
197 NETLINK_FAMILY nlPacketFamilyOps = {
198     .name     = OVS_PACKET_FAMILY,
199     .id       = OVS_WIN_NL_PACKET_FAMILY_ID,
200     .version  = OVS_PACKET_VERSION,
201     .maxAttr  = OVS_PACKET_ATTR_MAX,
202     .cmds     = nlPacketFamilyCmdOps,
203     .opsCount = ARRAY_SIZE(nlPacketFamilyCmdOps)
204 };
205
206 /* Netlink vport family. */
207 NETLINK_CMD nlVportFamilyCmdOps[] = {
208     { .cmd = OVS_VPORT_CMD_GET,
209       .handler = OvsGetVportCmdHandler,
210       .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
211                         OVS_TRANSACTION_DEV_OP,
212       .validateDpIndex = TRUE
213     },
214     { .cmd = OVS_VPORT_CMD_NEW,
215       .handler = OvsNewVportCmdHandler,
216       .supportedDevOp = OVS_TRANSACTION_DEV_OP,
217       .validateDpIndex = TRUE
218     },
219     { .cmd = OVS_VPORT_CMD_SET,
220       .handler = OvsSetVportCmdHandler,
221       .supportedDevOp = OVS_TRANSACTION_DEV_OP,
222       .validateDpIndex = TRUE
223     },
224     { .cmd = OVS_VPORT_CMD_DEL,
225       .handler = OvsDeleteVportCmdHandler,
226       .supportedDevOp = OVS_TRANSACTION_DEV_OP,
227       .validateDpIndex = TRUE
228     },
229 };
230
231 NETLINK_FAMILY nlVportFamilyOps = {
232     .name     = OVS_VPORT_FAMILY,
233     .id       = OVS_WIN_NL_VPORT_FAMILY_ID,
234     .version  = OVS_VPORT_VERSION,
235     .maxAttr  = OVS_VPORT_ATTR_MAX,
236     .cmds     = nlVportFamilyCmdOps,
237     .opsCount = ARRAY_SIZE(nlVportFamilyCmdOps)
238 };
239
240 /* Netlink flow family. */
241
242 NETLINK_CMD nlFlowFamilyCmdOps[] = {
243     { .cmd              = OVS_FLOW_CMD_NEW,
244       .handler          = OvsFlowNlCmdHandler,
245       .supportedDevOp   = OVS_TRANSACTION_DEV_OP,
246       .validateDpIndex  = TRUE
247     },
248     { .cmd              = OVS_FLOW_CMD_SET,
249       .handler          = OvsFlowNlCmdHandler,
250       .supportedDevOp   = OVS_TRANSACTION_DEV_OP,
251       .validateDpIndex  = TRUE
252     },
253     { .cmd              = OVS_FLOW_CMD_DEL,
254       .handler          = OvsFlowNlCmdHandler,
255       .supportedDevOp   = OVS_TRANSACTION_DEV_OP,
256       .validateDpIndex  = TRUE
257     },
258     { .cmd              = OVS_FLOW_CMD_GET,
259       .handler          = OvsFlowNlGetCmdHandler,
260       .supportedDevOp   = OVS_TRANSACTION_DEV_OP |
261                           OVS_WRITE_DEV_OP | OVS_READ_DEV_OP,
262       .validateDpIndex  = TRUE
263     },
264 };
265
266 NETLINK_FAMILY nlFLowFamilyOps = {
267     .name     = OVS_FLOW_FAMILY,
268     .id       = OVS_WIN_NL_FLOW_FAMILY_ID,
269     .version  = OVS_FLOW_VERSION,
270     .maxAttr  = OVS_FLOW_ATTR_MAX,
271     .cmds     = nlFlowFamilyCmdOps,
272     .opsCount = ARRAY_SIZE(nlFlowFamilyCmdOps)
273 };
274
275 /* Netlink netdev family. */
276 NETLINK_CMD nlNetdevFamilyCmdOps[] = {
277     { .cmd = OVS_WIN_NETDEV_CMD_GET,
278       .handler = OvsGetNetdevCmdHandler,
279       .supportedDevOp = OVS_TRANSACTION_DEV_OP,
280       .validateDpIndex = FALSE
281     },
282 };
283
284 NETLINK_FAMILY nlNetdevFamilyOps = {
285     .name     = OVS_WIN_NETDEV_FAMILY,
286     .id       = OVS_WIN_NL_NETDEV_FAMILY_ID,
287     .version  = OVS_WIN_NETDEV_VERSION,
288     .maxAttr  = OVS_WIN_NETDEV_ATTR_MAX,
289     .cmds     = nlNetdevFamilyCmdOps,
290     .opsCount = ARRAY_SIZE(nlNetdevFamilyCmdOps)
291 };
292
293 static NTSTATUS MapIrpOutputBuffer(PIRP irp,
294                                    UINT32 bufferLength,
295                                    UINT32 requiredLength,
296                                    PVOID *buffer);
297 static NTSTATUS ValidateNetlinkCmd(UINT32 devOp,
298                                    POVS_OPEN_INSTANCE instance,
299                                    POVS_MESSAGE ovsMsg,
300                                    NETLINK_FAMILY *nlFamilyOps);
301 static NTSTATUS InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
302                                         NETLINK_FAMILY *nlFamilyOps,
303                                         UINT32 *replyLen);
304
305 /* Handles to the device object for communication with userspace. */
306 NDIS_HANDLE gOvsDeviceHandle;
307 PDEVICE_OBJECT gOvsDeviceObject;
308
309 _Dispatch_type_(IRP_MJ_CREATE)
310 _Dispatch_type_(IRP_MJ_CLOSE)
311 DRIVER_DISPATCH OvsOpenCloseDevice;
312
313 _Dispatch_type_(IRP_MJ_CLEANUP)
314 DRIVER_DISPATCH OvsCleanupDevice;
315
316 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
317 DRIVER_DISPATCH OvsDeviceControl;
318
319 #ifdef ALLOC_PRAGMA
320 #pragma alloc_text(INIT, OvsCreateDeviceObject)
321 #pragma alloc_text(PAGE, OvsOpenCloseDevice)
322 #pragma alloc_text(PAGE, OvsCleanupDevice)
323 #pragma alloc_text(PAGE, OvsDeviceControl)
324 #endif // ALLOC_PRAGMA
325
326 /*
327  * We might hit this limit easily since userspace opens a netlink descriptor for
328  * each thread, and at least one descriptor per vport. Revisit this later.
329  */
330 #define OVS_MAX_OPEN_INSTANCES 512
331 #define OVS_SYSTEM_DP_NAME     "ovs-system"
332
333 POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
334 UINT32 ovsNumberOfOpenInstances;
335 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
336
337 NDIS_SPIN_LOCK ovsCtrlLockObj;
338 PNDIS_SPIN_LOCK gOvsCtrlLock;
339
340
341 VOID
342 OvsInit()
343 {
344     gOvsCtrlLock = &ovsCtrlLockObj;
345     NdisAllocateSpinLock(gOvsCtrlLock);
346     OvsInitEventQueue();
347     OvsUserInit();
348 }
349
350 VOID
351 OvsCleanup()
352 {
353     OvsCleanupEventQueue();
354     if (gOvsCtrlLock) {
355         NdisFreeSpinLock(gOvsCtrlLock);
356         gOvsCtrlLock = NULL;
357     }
358     OvsUserCleanup();
359 }
360
361 VOID
362 OvsAcquireCtrlLock()
363 {
364     NdisAcquireSpinLock(gOvsCtrlLock);
365 }
366
367 VOID
368 OvsReleaseCtrlLock()
369 {
370     NdisReleaseSpinLock(gOvsCtrlLock);
371 }
372
373
374 /*
375  * --------------------------------------------------------------------------
376  * Creates the communication device between user and kernel, and also
377  * initializes the data associated data structures.
378  * --------------------------------------------------------------------------
379  */
380 NDIS_STATUS
381 OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
382 {
383     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
384     UNICODE_STRING deviceName;
385     UNICODE_STRING symbolicDeviceName;
386     PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
387     NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes;
388     OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle);
389
390     RtlZeroMemory(dispatchTable,
391                   (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH));
392     dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice;
393     dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice;
394     dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice;
395     dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl;
396
397     NdisInitUnicodeString(&deviceName, OVS_DEVICE_NAME_NT);
398     NdisInitUnicodeString(&symbolicDeviceName, OVS_DEVICE_NAME_DOS);
399
400     RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
401
402     OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header,
403                            NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
404                            NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
405                            sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
406
407     deviceAttributes.DeviceName = &deviceName;
408     deviceAttributes.SymbolicName = &symbolicDeviceName;
409     deviceAttributes.MajorFunctions = dispatchTable;
410     deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION);
411
412     status = NdisRegisterDeviceEx(ovsExtDriverHandle,
413                                   &deviceAttributes,
414                                   &gOvsDeviceObject,
415                                   &gOvsDeviceHandle);
416     if (status != NDIS_STATUS_SUCCESS) {
417         POVS_DEVICE_EXTENSION ovsExt =
418             (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(gOvsDeviceObject);
419         ASSERT(gOvsDeviceObject != NULL);
420         ASSERT(gOvsDeviceHandle != NULL);
421
422         if (ovsExt) {
423             ovsExt->numberOpenInstance = 0;
424         }
425     } else {
426         /* Initialize the associated data structures. */
427         OvsInit();
428     }
429     OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
430     return status;
431 }
432
433
434 VOID
435 OvsDeleteDeviceObject()
436 {
437     if (gOvsDeviceHandle) {
438 #ifdef DBG
439         POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)
440                     NdisGetDeviceReservedExtension(gOvsDeviceObject);
441         if (ovsExt) {
442             ASSERT(ovsExt->numberOpenInstance == 0);
443         }
444 #endif
445
446         ASSERT(gOvsDeviceObject);
447         NdisDeregisterDeviceEx(gOvsDeviceHandle);
448         gOvsDeviceHandle = NULL;
449         gOvsDeviceObject = NULL;
450     }
451     OvsCleanup();
452 }
453
454 POVS_OPEN_INSTANCE
455 OvsGetOpenInstance(PFILE_OBJECT fileObject,
456                    UINT32 dpNo)
457 {
458     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
459     ASSERT(instance);
460     ASSERT(instance->fileObject == fileObject);
461     if (gOvsSwitchContext == NULL ||
462         gOvsSwitchContext->dpNo != dpNo) {
463         return NULL;
464     }
465     return instance;
466 }
467
468
469 POVS_OPEN_INSTANCE
470 OvsFindOpenInstance(PFILE_OBJECT fileObject)
471 {
472     UINT32 i, j;
473     for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES &&
474                        j < ovsNumberOfOpenInstances; i++) {
475         if (ovsOpenInstanceArray[i]) {
476             if (ovsOpenInstanceArray[i]->fileObject == fileObject) {
477                 return ovsOpenInstanceArray[i];
478             }
479             j++;
480         }
481     }
482     return NULL;
483 }
484
485 NTSTATUS
486 OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
487                    PFILE_OBJECT fileObject)
488 {
489     POVS_OPEN_INSTANCE instance =
490         (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE));
491     UINT32 i;
492
493     if (instance == NULL) {
494         return STATUS_NO_MEMORY;
495     }
496     OvsAcquireCtrlLock();
497     ASSERT(OvsFindOpenInstance(fileObject) == NULL);
498
499     if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
500         OvsReleaseCtrlLock();
501         OvsFreeMemory(instance);
502         return STATUS_INSUFFICIENT_RESOURCES;
503     }
504     RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
505
506     for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) {
507         if (ovsOpenInstanceArray[i] == NULL) {
508             ovsOpenInstanceArray[i] = instance;
509             ovsNumberOfOpenInstances++;
510             instance->cookie = i;
511             break;
512         }
513     }
514     ASSERT(i < OVS_MAX_OPEN_INSTANCES);
515     instance->fileObject = fileObject;
516     ASSERT(fileObject->FsContext == NULL);
517     instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
518     if (instance->pid == 0) {
519         /* XXX: check for rollover. */
520     }
521     fileObject->FsContext = instance;
522     OvsReleaseCtrlLock();
523     return STATUS_SUCCESS;
524 }
525
526 static VOID
527 OvsCleanupOpenInstance(PFILE_OBJECT fileObject)
528 {
529     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
530     ASSERT(instance);
531     ASSERT(fileObject == instance->fileObject);
532     OvsCleanupEvent(instance);
533     OvsCleanupPacketQueue(instance);
534 }
535
536 VOID
537 OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
538 {
539     POVS_OPEN_INSTANCE instance;
540     ASSERT(fileObject->FsContext);
541     instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
542     ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES);
543
544     OvsAcquireCtrlLock();
545     fileObject->FsContext = NULL;
546     ASSERT(ovsOpenInstanceArray[instance->cookie] == instance);
547     ovsOpenInstanceArray[instance->cookie] = NULL;
548     ovsNumberOfOpenInstances--;
549     OvsReleaseCtrlLock();
550     ASSERT(instance->eventQueue == NULL);
551     ASSERT (instance->packetQueue == NULL);
552     OvsFreeMemory(instance);
553 }
554
555 NTSTATUS
556 OvsCompleteIrpRequest(PIRP irp,
557                       ULONG_PTR infoPtr,
558                       NTSTATUS status)
559 {
560     irp->IoStatus.Information = infoPtr;
561     irp->IoStatus.Status = status;
562     IoCompleteRequest(irp, IO_NO_INCREMENT);
563     return status;
564 }
565
566
567 NTSTATUS
568 OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject,
569                    PIRP irp)
570 {
571     PIO_STACK_LOCATION irpSp;
572     NTSTATUS status = STATUS_SUCCESS;
573     PFILE_OBJECT fileObject;
574     POVS_DEVICE_EXTENSION ovsExt =
575         (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
576
577     ASSERT(deviceObject == gOvsDeviceObject);
578     ASSERT(ovsExt != NULL);
579
580     irpSp = IoGetCurrentIrpStackLocation(irp);
581     fileObject = irpSp->FileObject;
582     OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u",
583                   deviceObject, fileObject,
584                   ovsExt->numberOpenInstance);
585
586     switch (irpSp->MajorFunction) {
587     case IRP_MJ_CREATE:
588         status = OvsAddOpenInstance(ovsExt, fileObject);
589         if (STATUS_SUCCESS == status) {
590             InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance);
591         }
592         break;
593     case IRP_MJ_CLOSE:
594         ASSERT(ovsExt->numberOpenInstance > 0);
595         OvsRemoveOpenInstance(fileObject);
596         InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance);
597         break;
598     default:
599         ASSERT(0);
600     }
601     return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
602 }
603
604 _Use_decl_annotations_
605 NTSTATUS
606 OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
607                  PIRP irp)
608 {
609
610     PIO_STACK_LOCATION irpSp;
611     PFILE_OBJECT fileObject;
612
613     NTSTATUS status = STATUS_SUCCESS;
614 #ifdef DBG
615     POVS_DEVICE_EXTENSION ovsExt =
616         (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
617     if (ovsExt) {
618         ASSERT(ovsExt->numberOpenInstance > 0);
619     }
620 #else
621     UNREFERENCED_PARAMETER(deviceObject);
622 #endif
623     ASSERT(deviceObject == gOvsDeviceObject);
624     irpSp = IoGetCurrentIrpStackLocation(irp);
625     fileObject = irpSp->FileObject;
626
627     ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP);
628
629     OvsCleanupOpenInstance(fileObject);
630
631     return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
632 }
633
634
635 /*
636  * --------------------------------------------------------------------------
637  * IOCTL function handler for the device.
638  * --------------------------------------------------------------------------
639  */
640 NTSTATUS
641 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
642                  PIRP irp)
643 {
644
645     PIO_STACK_LOCATION irpSp;
646     NTSTATUS status = STATUS_SUCCESS;
647     PFILE_OBJECT fileObject;
648     PVOID inputBuffer = NULL;
649     PVOID outputBuffer = NULL;
650     UINT32 inputBufferLen, outputBufferLen;
651     UINT32 code, replyLen = 0;
652     POVS_OPEN_INSTANCE instance;
653     UINT32 devOp;
654     OVS_MESSAGE ovsMsgReadOp;
655     POVS_MESSAGE ovsMsg;
656     NETLINK_FAMILY *nlFamilyOps;
657     OVS_USER_PARAMS_CONTEXT usrParamsCtx;
658
659 #ifdef DBG
660     POVS_DEVICE_EXTENSION ovsExt =
661         (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
662     ASSERT(deviceObject == gOvsDeviceObject);
663     ASSERT(ovsExt);
664     ASSERT(ovsExt->numberOpenInstance > 0);
665 #else
666     UNREFERENCED_PARAMETER(deviceObject);
667 #endif
668
669     irpSp = IoGetCurrentIrpStackLocation(irp);
670
671     ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
672     ASSERT(irpSp->FileObject != NULL);
673
674     fileObject = irpSp->FileObject;
675     instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
676     code = irpSp->Parameters.DeviceIoControl.IoControlCode;
677     inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
678     outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
679     inputBuffer = irp->AssociatedIrp.SystemBuffer;
680
681     /* Concurrent netlink operations are not supported. */
682     if (InterlockedCompareExchange((LONG volatile *)&instance->inUse, 1, 0)) {
683         status = STATUS_RESOURCE_IN_USE;
684         goto done;
685     }
686
687     /*
688      * Validate the input/output buffer arguments depending on the type of the
689      * operation.
690      */
691     switch (code) {
692     case OVS_IOCTL_TRANSACT:
693         /* Input buffer is mandatory, output buffer is optional. */
694         if (outputBufferLen != 0) {
695             status = MapIrpOutputBuffer(irp, outputBufferLen,
696                                         sizeof *ovsMsg, &outputBuffer);
697             if (status != STATUS_SUCCESS) {
698                 goto done;
699             }
700             ASSERT(outputBuffer);
701         }
702
703         if (inputBufferLen < sizeof (*ovsMsg)) {
704             status = STATUS_NDIS_INVALID_LENGTH;
705             goto done;
706         }
707
708         ovsMsg = inputBuffer;
709         devOp = OVS_TRANSACTION_DEV_OP;
710         break;
711
712     case OVS_IOCTL_READ_EVENT:
713     case OVS_IOCTL_READ_PACKET:
714         /* This IOCTL is used to read events */
715         if (outputBufferLen != 0) {
716             status = MapIrpOutputBuffer(irp, outputBufferLen,
717                                         sizeof *ovsMsg, &outputBuffer);
718             if (status != STATUS_SUCCESS) {
719                 goto done;
720             }
721             ASSERT(outputBuffer);
722         } else {
723             status = STATUS_NDIS_INVALID_LENGTH;
724             goto done;
725         }
726         inputBuffer = NULL;
727         inputBufferLen = 0;
728
729         ovsMsg = &ovsMsgReadOp;
730         ovsMsg->nlMsg.nlmsgType = OVS_WIN_NL_CTRL_FAMILY_ID;
731         /* An "artificial" command so we can use NL family function table*/
732         ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
733                               OVS_CTRL_CMD_EVENT_NOTIFY :
734                               OVS_CTRL_CMD_READ_NOTIFY;
735         devOp = OVS_READ_DEV_OP;
736         break;
737
738     case OVS_IOCTL_READ:
739         /* Output buffer is mandatory. */
740         if (outputBufferLen != 0) {
741             status = MapIrpOutputBuffer(irp, outputBufferLen,
742                                         sizeof *ovsMsg, &outputBuffer);
743             if (status != STATUS_SUCCESS) {
744                 goto done;
745             }
746             ASSERT(outputBuffer);
747         } else {
748             status = STATUS_NDIS_INVALID_LENGTH;
749             goto done;
750         }
751
752         /*
753          * Operate in the mode that read ioctl is similar to ReadFile(). This
754          * might change as the userspace code gets implemented.
755          */
756         inputBuffer = NULL;
757         inputBufferLen = 0;
758
759         /*
760          * For implementing read (ioctl or otherwise), we need to store some
761          * state in the instance to indicate the command that started the dump
762          * operation. The state can setup 'ovsMsgReadOp' appropriately. Note
763          * that 'ovsMsgReadOp' is needed only in this function to call into the
764          * appropraite handler. The handler itself can access the state in the
765          * instance.
766          *
767          * In the absence of a dump start, return 0 bytes.
768          */
769         if (instance->dumpState.ovsMsg == NULL) {
770             replyLen = 0;
771             status = STATUS_SUCCESS;
772             goto done;
773         }
774         RtlCopyMemory(&ovsMsgReadOp, instance->dumpState.ovsMsg,
775                       sizeof (ovsMsgReadOp));
776
777         /* Create an NL message for consumption. */
778         ovsMsg = &ovsMsgReadOp;
779         devOp = OVS_READ_DEV_OP;
780
781         break;
782
783     case OVS_IOCTL_WRITE:
784         /* Input buffer is mandatory. */
785         if (inputBufferLen < sizeof (*ovsMsg)) {
786             status = STATUS_NDIS_INVALID_LENGTH;
787             goto done;
788         }
789
790         ovsMsg = inputBuffer;
791         devOp = OVS_WRITE_DEV_OP;
792         break;
793
794     default:
795         status = STATUS_INVALID_DEVICE_REQUEST;
796         goto done;
797     }
798
799     ASSERT(ovsMsg);
800     switch (ovsMsg->nlMsg.nlmsgType) {
801     case OVS_WIN_NL_CTRL_FAMILY_ID:
802         nlFamilyOps = &nlControlFamilyOps;
803         break;
804     case OVS_WIN_NL_DATAPATH_FAMILY_ID:
805         nlFamilyOps = &nlDatapathFamilyOps;
806         break;
807     case OVS_WIN_NL_FLOW_FAMILY_ID:
808          nlFamilyOps = &nlFLowFamilyOps;
809          break;
810     case OVS_WIN_NL_PACKET_FAMILY_ID:
811          nlFamilyOps = &nlPacketFamilyOps;
812          break;
813     case OVS_WIN_NL_VPORT_FAMILY_ID:
814         nlFamilyOps = &nlVportFamilyOps;
815         break;
816     case OVS_WIN_NL_NETDEV_FAMILY_ID:
817         nlFamilyOps = &nlNetdevFamilyOps;
818         break;
819     default:
820         status = STATUS_INVALID_PARAMETER;
821         goto done;
822     }
823
824     /*
825      * For read operation, the netlink command has already been validated
826      * previously.
827      */
828     if (devOp != OVS_READ_DEV_OP) {
829         status = ValidateNetlinkCmd(devOp, instance, ovsMsg, nlFamilyOps);
830         if (status != STATUS_SUCCESS) {
831             goto done;
832         }
833     }
834
835     InitUserParamsCtx(irp, instance, devOp, ovsMsg,
836                       inputBuffer, inputBufferLen,
837                       outputBuffer, outputBufferLen,
838                       &usrParamsCtx);
839
840     status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
841
842 done:
843     KeMemoryBarrier();
844     instance->inUse = 0;
845     return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
846 }
847
848
849 /*
850  * --------------------------------------------------------------------------
851  * Function to validate a netlink command. Only certain combinations of
852  * (device operation, netlink family, command) are valid.
853  * --------------------------------------------------------------------------
854  */
855 static NTSTATUS
856 ValidateNetlinkCmd(UINT32 devOp,
857                    POVS_OPEN_INSTANCE instance,
858                    POVS_MESSAGE ovsMsg,
859                    NETLINK_FAMILY *nlFamilyOps)
860 {
861     NTSTATUS status = STATUS_INVALID_PARAMETER;
862     UINT16 i;
863
864     for (i = 0; i < nlFamilyOps->opsCount; i++) {
865         if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
866             /* Validate if the command is valid for the device operation. */
867             if ((devOp & nlFamilyOps->cmds[i].supportedDevOp) == 0) {
868                 status = STATUS_INVALID_PARAMETER;
869                 goto done;
870             }
871
872             /* Validate the version. */
873             if (nlFamilyOps->version > ovsMsg->genlMsg.version) {
874                 status = STATUS_INVALID_PARAMETER;
875                 goto done;
876             }
877
878             /* Validate the DP for commands that require a DP. */
879             if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
880                 OvsAcquireCtrlLock();
881                 if (ovsMsg->ovsHdr.dp_ifindex !=
882                     (INT)gOvsSwitchContext->dpNo) {
883                     status = STATUS_INVALID_PARAMETER;
884                     OvsReleaseCtrlLock();
885                     goto done;
886                 }
887                 OvsReleaseCtrlLock();
888             }
889
890             /* Validate the PID. */
891             if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) {
892                 if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
893                     status = STATUS_INVALID_PARAMETER;
894                     goto done;
895                 }
896             }
897
898             status = STATUS_SUCCESS;
899             break;
900         }
901     }
902
903 done:
904     return status;
905 }
906
907 /*
908  * --------------------------------------------------------------------------
909  * Function to invoke the netlink command handler.
910  * --------------------------------------------------------------------------
911  */
912 static NTSTATUS
913 InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
914                         NETLINK_FAMILY *nlFamilyOps,
915                         UINT32 *replyLen)
916 {
917     NTSTATUS status = STATUS_INVALID_PARAMETER;
918     UINT16 i;
919
920     for (i = 0; i < nlFamilyOps->opsCount; i++) {
921         if (nlFamilyOps->cmds[i].cmd == usrParamsCtx->ovsMsg->genlMsg.cmd) {
922             NetlinkCmdHandler *handler = nlFamilyOps->cmds[i].handler;
923             ASSERT(handler);
924             if (handler) {
925                 status = handler(usrParamsCtx, replyLen);
926             }
927             break;
928         }
929     }
930
931     return status;
932 }
933
934 /*
935  * --------------------------------------------------------------------------
936  *  Command Handler for 'OVS_CTRL_CMD_WIN_GET_PID'.
937  *
938  *  Each handle on the device is assigned a unique PID when the handle is
939  *  created. On platforms that support netlink natively, the PID is available
940  *  to userspace when the netlink socket is created. However, without native
941  *  netlink support on Windows, OVS datapath generates the PID and lets the
942  *  userspace query it.
943  *
944  *  This function implements the query.
945  * --------------------------------------------------------------------------
946  */
947 static NTSTATUS
948 OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
949                     UINT32 *replyLen)
950 {
951     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
952     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
953
954     if (usrParamsCtx->outputLength >= sizeof *msgOut) {
955         POVS_OPEN_INSTANCE instance =
956             (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
957
958         RtlZeroMemory(msgOut, sizeof *msgOut);
959         msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
960         msgOut->nlMsg.nlmsgPid = instance->pid;
961         *replyLen = sizeof *msgOut;
962         /* XXX: We might need to return the DP index as well. */
963     } else {
964         return STATUS_NDIS_INVALID_LENGTH;
965     }
966
967     return STATUS_SUCCESS;
968 }
969
970 /*
971  * --------------------------------------------------------------------------
972  * Utility function to fill up information about the datapath in a reply to
973  * userspace.
974  * Assumes that 'gOvsCtrlLock' lock is acquired.
975  * --------------------------------------------------------------------------
976  */
977 static NTSTATUS
978 OvsDpFillInfo(POVS_SWITCH_CONTEXT ovsSwitchContext,
979               POVS_MESSAGE msgIn,
980               PNL_BUFFER nlBuf)
981 {
982     BOOLEAN writeOk;
983     OVS_MESSAGE msgOutTmp;
984     OVS_DATAPATH *datapath = &ovsSwitchContext->datapath;
985     PNL_MSG_HDR nlMsg;
986
987     ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && NlBufRemLen(nlBuf) >= sizeof *msgIn);
988
989     msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_DATAPATH_FAMILY_ID;
990     msgOutTmp.nlMsg.nlmsgFlags = 0;  /* XXX: ? */
991     msgOutTmp.nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
992     msgOutTmp.nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
993
994     msgOutTmp.genlMsg.cmd = OVS_DP_CMD_GET;
995     msgOutTmp.genlMsg.version = nlDatapathFamilyOps.version;
996     msgOutTmp.genlMsg.reserved = 0;
997
998     msgOutTmp.ovsHdr.dp_ifindex = ovsSwitchContext->dpNo;
999
1000     writeOk = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1001     if (writeOk) {
1002         writeOk = NlMsgPutTailString(nlBuf, OVS_DP_ATTR_NAME,
1003                                      OVS_SYSTEM_DP_NAME);
1004     }
1005     if (writeOk) {
1006         OVS_DP_STATS dpStats;
1007
1008         dpStats.n_hit = datapath->hits;
1009         dpStats.n_missed = datapath->misses;
1010         dpStats.n_lost = datapath->lost;
1011         dpStats.n_flows = datapath->nFlows;
1012         writeOk = NlMsgPutTailUnspec(nlBuf, OVS_DP_ATTR_STATS,
1013                                      (PCHAR)&dpStats, sizeof dpStats);
1014     }
1015     nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1016     nlMsg->nlmsgLen = NlBufSize(nlBuf);
1017
1018     return writeOk ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE;
1019 }
1020
1021 /*
1022  * --------------------------------------------------------------------------
1023  * Handler for queueing an IRP used for event notification. The IRP is
1024  * completed when a port state changes. STATUS_PENDING is returned on
1025  * success. User mode keep a pending IRP at all times.
1026  * --------------------------------------------------------------------------
1027  */
1028 static NTSTATUS
1029 OvsPendEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1030                        UINT32 *replyLen)
1031 {
1032     NDIS_STATUS status;
1033
1034     UNREFERENCED_PARAMETER(replyLen);
1035
1036     POVS_OPEN_INSTANCE instance =
1037         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1038     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1039     OVS_EVENT_POLL poll;
1040
1041     poll.dpNo = msgIn->ovsHdr.dp_ifindex;
1042     status = OvsWaitEventIoctl(usrParamsCtx->irp, instance->fileObject,
1043                                &poll, sizeof poll);
1044     return status;
1045 }
1046
1047 /*
1048  * --------------------------------------------------------------------------
1049  *  Handler for the subscription for the event queue
1050  * --------------------------------------------------------------------------
1051  */
1052 static NTSTATUS
1053 OvsSubscribeEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1054                             UINT32 *replyLen)
1055 {
1056     NDIS_STATUS status;
1057     OVS_EVENT_SUBSCRIBE request;
1058     BOOLEAN rc;
1059     UINT8 join;
1060     PNL_ATTR attrs[2];
1061     const NL_POLICY policy[] =  {
1062         [OVS_NL_ATTR_MCAST_GRP] = {.type = NL_A_U32 },
1063         [OVS_NL_ATTR_MCAST_JOIN] = {.type = NL_A_U8 },
1064         };
1065
1066     UNREFERENCED_PARAMETER(replyLen);
1067
1068     POVS_OPEN_INSTANCE instance =
1069         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1070     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1071
1072     rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1073          NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, attrs, 2);
1074     if (!rc) {
1075         status = STATUS_INVALID_PARAMETER;
1076         goto done;
1077     }
1078
1079     /* XXX Ignore the MC group for now */
1080     join = NlAttrGetU8(attrs[OVS_NL_ATTR_MCAST_JOIN]);
1081     request.dpNo = msgIn->ovsHdr.dp_ifindex;
1082     request.subscribe = join;
1083     request.mask = OVS_EVENT_MASK_ALL;
1084
1085     status = OvsSubscribeEventIoctl(instance->fileObject, &request,
1086                                     sizeof request);
1087 done:
1088     return status;
1089 }
1090
1091 /*
1092  * --------------------------------------------------------------------------
1093  *  Command Handler for 'OVS_DP_CMD_NEW'.
1094  * --------------------------------------------------------------------------
1095  */
1096 static NTSTATUS
1097 OvsNewDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1098                    UINT32 *replyLen)
1099 {
1100     return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1101 }
1102
1103 /*
1104  * --------------------------------------------------------------------------
1105  *  Command Handler for 'OVS_DP_CMD_GET'.
1106  *
1107  *  The function handles both the dump based as well as the transaction based
1108  *  'OVS_DP_CMD_GET' command. In the dump command, it handles the initial
1109  *  call to setup dump state, as well as subsequent calls to continue dumping
1110  *  data.
1111  * --------------------------------------------------------------------------
1112  */
1113 static NTSTATUS
1114 OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1115                    UINT32 *replyLen)
1116 {
1117     if (usrParamsCtx->devOp == OVS_TRANSACTION_DEV_OP) {
1118         return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1119     } else {
1120         return HandleGetDpDump(usrParamsCtx, replyLen);
1121     }
1122 }
1123
1124 /*
1125  * --------------------------------------------------------------------------
1126  *  Function for handling the transaction based 'OVS_DP_CMD_GET' command.
1127  * --------------------------------------------------------------------------
1128  */
1129 static NTSTATUS
1130 HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1131                        UINT32 *replyLen)
1132 {
1133     return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1134 }
1135
1136
1137 /*
1138  * --------------------------------------------------------------------------
1139  *  Function for handling the dump-based 'OVS_DP_CMD_GET' command.
1140  * --------------------------------------------------------------------------
1141  */
1142 static NTSTATUS
1143 HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1144                 UINT32 *replyLen)
1145 {
1146     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1147     POVS_OPEN_INSTANCE instance =
1148         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1149
1150     if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
1151         *replyLen = 0;
1152         OvsSetupDumpStart(usrParamsCtx);
1153     } else {
1154         NL_BUFFER nlBuf;
1155         NTSTATUS status;
1156         POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
1157
1158         ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1159
1160         if (instance->dumpState.ovsMsg == NULL) {
1161             ASSERT(FALSE);
1162             return STATUS_INVALID_DEVICE_STATE;
1163         }
1164
1165         /* Dump state must have been deleted after previous dump operation. */
1166         ASSERT(instance->dumpState.index[0] == 0);
1167         /* Output buffer has been validated while validating read dev op. */
1168         ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1169
1170         NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
1171                   usrParamsCtx->outputLength);
1172
1173         OvsAcquireCtrlLock();
1174         if (!gOvsSwitchContext) {
1175             /* Treat this as a dump done. */
1176             OvsReleaseCtrlLock();
1177             *replyLen = 0;
1178             FreeUserDumpState(instance);
1179             return STATUS_SUCCESS;
1180         }
1181         status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1182         OvsReleaseCtrlLock();
1183
1184         if (status != STATUS_SUCCESS) {
1185             *replyLen = 0;
1186             FreeUserDumpState(instance);
1187             return status;
1188         }
1189
1190         /* Increment the dump index. */
1191         instance->dumpState.index[0] = 1;
1192         *replyLen = msgOut->nlMsg.nlmsgLen;
1193
1194         /* Free up the dump state, since there's no more data to continue. */
1195         FreeUserDumpState(instance);
1196     }
1197
1198     return STATUS_SUCCESS;
1199 }
1200
1201
1202 /*
1203  * --------------------------------------------------------------------------
1204  *  Command Handler for 'OVS_DP_CMD_SET'.
1205  * --------------------------------------------------------------------------
1206  */
1207 static NTSTATUS
1208 OvsSetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1209                    UINT32 *replyLen)
1210 {
1211     return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1212 }
1213
1214 /*
1215  * --------------------------------------------------------------------------
1216  *  Function for handling transaction based 'OVS_DP_CMD_NEW', 'OVS_DP_CMD_GET'
1217  *  and 'OVS_DP_CMD_SET' commands.
1218  *
1219  * 'OVS_DP_CMD_NEW' is implemented to keep userspace code happy. Creation of a
1220  * new datapath is not supported currently.
1221  * --------------------------------------------------------------------------
1222  */
1223 static NTSTATUS
1224 HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1225                           UINT32 *replyLen)
1226 {
1227     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1228     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1229     NTSTATUS status = STATUS_SUCCESS;
1230     NL_BUFFER nlBuf;
1231     NL_ERROR nlError = NL_ERROR_SUCCESS;
1232     static const NL_POLICY ovsDatapathSetPolicy[] = {
1233         [OVS_DP_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ },
1234         [OVS_DP_ATTR_UPCALL_PID] = { .type = NL_A_U32, .optional = TRUE },
1235         [OVS_DP_ATTR_USER_FEATURES] = { .type = NL_A_U32, .optional = TRUE },
1236     };
1237     PNL_ATTR dpAttrs[ARRAY_SIZE(ovsDatapathSetPolicy)];
1238
1239     /* input buffer has been validated while validating write dev op. */
1240     ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1241
1242     /* Parse any attributes in the request. */
1243     if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET ||
1244         usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1245         if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1246                         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1247                         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1248                         ovsDatapathSetPolicy, dpAttrs, ARRAY_SIZE(dpAttrs))) {
1249             return STATUS_INVALID_PARAMETER;
1250         }
1251
1252         /*
1253         * XXX: Not clear at this stage if there's any role for the
1254         * OVS_DP_ATTR_UPCALL_PID and OVS_DP_ATTR_USER_FEATURES attributes passed
1255         * from userspace.
1256         */
1257
1258     } else {
1259         RtlZeroMemory(dpAttrs, sizeof dpAttrs);
1260     }
1261
1262     /* Output buffer is optional for OVS_TRANSACTION_DEV_OP. */
1263     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1264         return STATUS_NDIS_INVALID_LENGTH;
1265     }
1266     NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1267
1268     OvsAcquireCtrlLock();
1269     if (dpAttrs[OVS_DP_ATTR_NAME] != NULL) {
1270         if (!gOvsSwitchContext &&
1271             !OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
1272                               OVS_SYSTEM_DP_NAME)) {
1273             OvsReleaseCtrlLock();
1274
1275             /* Creation of new datapaths is not supported. */
1276             if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET) {
1277                 nlError = NL_ERROR_NOTSUPP;
1278                 goto cleanup;
1279             }
1280
1281             nlError = NL_ERROR_NODEV;
1282             goto cleanup;
1283         }
1284     } else if ((UINT32)msgIn->ovsHdr.dp_ifindex != gOvsSwitchContext->dpNo) {
1285         OvsReleaseCtrlLock();
1286         nlError = NL_ERROR_NODEV;
1287         goto cleanup;
1288     }
1289
1290     if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1291         OvsReleaseCtrlLock();
1292         nlError = NL_ERROR_EXIST;
1293         goto cleanup;
1294     }
1295
1296     status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1297     OvsReleaseCtrlLock();
1298
1299     *replyLen = NlBufSize(&nlBuf);
1300
1301 cleanup:
1302     if (nlError != NL_ERROR_SUCCESS) {
1303         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1304             usrParamsCtx->outputBuffer;
1305
1306         BuildErrorMsg(msgIn, msgError, nlError);
1307         *replyLen = msgError->nlMsg.nlmsgLen;
1308     }
1309
1310     return STATUS_SUCCESS;
1311 }
1312
1313
1314 NTSTATUS
1315 OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
1316 {
1317     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1318     POVS_OPEN_INSTANCE instance =
1319         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1320
1321     /* input buffer has been validated while validating write dev op. */
1322     ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1323
1324     /* A write operation that does not indicate dump start is invalid. */
1325     if ((msgIn->nlMsg.nlmsgFlags & NLM_F_DUMP) != NLM_F_DUMP) {
1326         return STATUS_INVALID_PARAMETER;
1327     }
1328     /* XXX: Handle other NLM_F_* flags in the future. */
1329
1330     /*
1331      * This operation should be setting up the dump state. If there's any
1332      * previous state, clear it up so as to set it up afresh.
1333      */
1334     if (instance->dumpState.ovsMsg != NULL) {
1335         FreeUserDumpState(instance);
1336     }
1337
1338     return InitUserDumpState(instance, msgIn);
1339 }
1340
1341 static VOID
1342 BuildMsgOut(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16 type,
1343             UINT32 length, UINT16 flags)
1344 {
1345     msgOut->nlMsg.nlmsgType = type;
1346     msgOut->nlMsg.nlmsgFlags = flags;
1347     msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
1348     msgOut->nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
1349     msgOut->nlMsg.nlmsgLen = length;
1350
1351     msgOut->genlMsg.cmd = msgIn->genlMsg.cmd;
1352     msgOut->genlMsg.version = msgIn->genlMsg.version;
1353     msgOut->genlMsg.reserved = 0;
1354 }
1355
1356 /*
1357  * XXX: should move out these functions to a Netlink.c or to a OvsMessage.c
1358  * or even make them inlined functions in Datapath.h. Can be done after the
1359  * first sprint once we have more code to refactor.
1360  */
1361 VOID
1362 BuildReplyMsgFromMsgIn(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16 flags)
1363 {
1364     BuildMsgOut(msgIn, msgOut, msgIn->nlMsg.nlmsgType, sizeof(OVS_MESSAGE),
1365                 flags);
1366 }
1367
1368 VOID
1369 BuildErrorMsg(POVS_MESSAGE msgIn, POVS_MESSAGE_ERROR msgOut, UINT errorCode)
1370 {
1371     BuildMsgOut(msgIn, (POVS_MESSAGE)msgOut, NLMSG_ERROR,
1372                 sizeof(OVS_MESSAGE_ERROR), 0);
1373
1374     msgOut->errorMsg.error = errorCode;
1375     msgOut->errorMsg.nlMsg = msgIn->nlMsg;
1376 }
1377
1378 static NTSTATUS
1379 OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
1380                       POVS_MESSAGE msgIn,
1381                       PVOID outBuffer,
1382                       UINT32 outBufLen,
1383                       int dpIfIndex)
1384 {
1385     NL_BUFFER nlBuffer;
1386     OVS_VPORT_FULL_STATS vportStats;
1387     BOOLEAN ok;
1388     OVS_MESSAGE msgOut;
1389     PNL_MSG_HDR nlMsg;
1390
1391     NlBufInit(&nlBuffer, outBuffer, outBufLen);
1392
1393     BuildReplyMsgFromMsgIn(msgIn, &msgOut, NLM_F_MULTI);
1394     msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1395
1396     ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1397     if (!ok) {
1398         return STATUS_INSUFFICIENT_RESOURCES;
1399     }
1400
1401     ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
1402     if (!ok) {
1403         return STATUS_INSUFFICIENT_RESOURCES;
1404     }
1405
1406     ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
1407     if (!ok) {
1408         return STATUS_INSUFFICIENT_RESOURCES;
1409     }
1410
1411     ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
1412     if (!ok) {
1413         return STATUS_INSUFFICIENT_RESOURCES;
1414     }
1415
1416     /*
1417      * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1418      * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1419      * it means we have an array of pids, instead of a single pid.
1420      * ATM we assume we have one pid only.
1421     */
1422
1423     ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
1424                          vport->upcallPid);
1425     if (!ok) {
1426         return STATUS_INSUFFICIENT_RESOURCES;
1427     }
1428
1429     /*stats*/
1430     vportStats.rxPackets = vport->stats.rxPackets;
1431     vportStats.rxBytes = vport->stats.rxBytes;
1432     vportStats.txPackets = vport->stats.txPackets;
1433     vportStats.txBytes = vport->stats.txBytes;
1434     vportStats.rxErrors = vport->errStats.rxErrors;
1435     vportStats.txErrors = vport->errStats.txErrors;
1436     vportStats.rxDropped = vport->errStats.rxDropped;
1437     vportStats.txDropped = vport->errStats.txDropped;
1438
1439     ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
1440                             (PCHAR)&vportStats,
1441                             sizeof(OVS_VPORT_FULL_STATS));
1442     if (!ok) {
1443         return STATUS_INSUFFICIENT_RESOURCES;
1444     }
1445
1446     /*
1447      * XXX: when vxlan udp dest port becomes configurable, we will also need
1448      * to add vport options
1449     */
1450
1451     nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1452     nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1453
1454     return STATUS_SUCCESS;
1455 }
1456
1457 static NTSTATUS
1458 OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1459                     UINT32 *replyLen)
1460 {
1461     POVS_MESSAGE msgIn;
1462     POVS_OPEN_INSTANCE instance =
1463         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1464     LOCK_STATE_EX lockState;
1465     UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
1466
1467     /*
1468      * XXX: this function shares some code with other dump command(s).
1469      * In the future, we will need to refactor the dump functions
1470     */
1471
1472     ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1473
1474     if (instance->dumpState.ovsMsg == NULL) {
1475         ASSERT(FALSE);
1476         return STATUS_INVALID_DEVICE_STATE;
1477     }
1478
1479     /* Output buffer has been validated while validating read dev op. */
1480     ASSERT(usrParamsCtx->outputBuffer != NULL);
1481
1482     msgIn = instance->dumpState.ovsMsg;
1483
1484     OvsAcquireCtrlLock();
1485     if (!gOvsSwitchContext) {
1486         /* Treat this as a dump done. */
1487         OvsReleaseCtrlLock();
1488         *replyLen = 0;
1489         FreeUserDumpState(instance);
1490         return STATUS_SUCCESS;
1491     }
1492
1493     /*
1494      * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1495      * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1496      * it means we have an array of pids, instead of a single pid.
1497      * ATM we assume we have one pid only.
1498     */
1499     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1500     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1501                           NDIS_RWL_AT_DISPATCH_LEVEL);
1502
1503     if (gOvsSwitchContext->numVports > 0) {
1504         /* inBucket: the bucket, used for lookup */
1505         UINT32 inBucket = instance->dumpState.index[0];
1506         /* inIndex: index within the given bucket, used for lookup */
1507         UINT32 inIndex = instance->dumpState.index[1];
1508         /* the bucket to be used for the next dump operation */
1509         UINT32 outBucket = 0;
1510         /* the index within the outBucket to be used for the next dump */
1511         UINT32 outIndex = 0;
1512
1513         for (i = inBucket; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
1514             PLIST_ENTRY head, link;
1515             head = &(gOvsSwitchContext->portIdHashArray[i]);
1516             POVS_VPORT_ENTRY vport = NULL;
1517
1518             outIndex = 0;
1519             LIST_FORALL(head, link) {
1520
1521                 /*
1522                  * if one or more dumps were previously done on this same bucket,
1523                  * inIndex will be > 0, so we'll need to reply with the
1524                  * inIndex + 1 vport from the bucket.
1525                 */
1526                 if (outIndex >= inIndex) {
1527                     vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
1528
1529                     if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
1530                         OvsCreateMsgFromVport(vport, msgIn,
1531                                               usrParamsCtx->outputBuffer,
1532                                               usrParamsCtx->outputLength,
1533                                               gOvsSwitchContext->dpNo);
1534                         ++outIndex;
1535                         break;
1536                     } else {
1537                         vport = NULL;
1538                     }
1539                 }
1540
1541                 ++outIndex;
1542             }
1543
1544             if (vport) {
1545                 break;
1546             }
1547
1548             /*
1549              * if no vport was found above, check the next bucket, beginning
1550              * with the first (i.e. index 0) elem from within that bucket
1551             */
1552             inIndex = 0;
1553         }
1554
1555         outBucket = i;
1556
1557         /* XXX: what about NLMSG_DONE (as msg type)? */
1558         instance->dumpState.index[0] = outBucket;
1559         instance->dumpState.index[1] = outIndex;
1560     }
1561
1562     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1563
1564     OvsReleaseCtrlLock();
1565
1566     /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
1567     if (i < OVS_MAX_VPORT_ARRAY_SIZE) {
1568         POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1569         *replyLen = msgOut->nlMsg.nlmsgLen;
1570     } else {
1571         /*
1572          * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
1573          * it's dump done
1574          */
1575         *replyLen = 0;
1576         /* Free up the dump state, since there's no more data to continue. */
1577         FreeUserDumpState(instance);
1578     }
1579
1580     return STATUS_SUCCESS;
1581 }
1582
1583 static NTSTATUS
1584 OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1585             UINT32 *replyLen)
1586 {
1587     NTSTATUS status = STATUS_SUCCESS;
1588     LOCK_STATE_EX lockState;
1589
1590     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1591     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1592     POVS_VPORT_ENTRY vport = NULL;
1593     NL_ERROR nlError = NL_ERROR_SUCCESS;
1594     PCHAR portName = NULL;
1595     UINT32 portNameLen = 0;
1596     UINT32 portNumber = OVS_DPPORT_NUMBER_INVALID;
1597
1598     static const NL_POLICY ovsVportPolicy[] = {
1599         [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
1600         [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING,
1601                                   .minLen = 2,
1602                                   .maxLen = IFNAMSIZ,
1603                                   .optional = TRUE},
1604     };
1605     PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
1606
1607     /* input buffer has been validated while validating write dev op. */
1608     ASSERT(usrParamsCtx->inputBuffer != NULL);
1609
1610     if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1611         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1612         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1613         ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
1614         return STATUS_INVALID_PARAMETER;
1615     }
1616
1617     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1618         return STATUS_INVALID_BUFFER_SIZE;
1619     }
1620
1621     OvsAcquireCtrlLock();
1622     if (!gOvsSwitchContext) {
1623         OvsReleaseCtrlLock();
1624         return STATUS_INVALID_PARAMETER;
1625     }
1626     OvsReleaseCtrlLock();
1627
1628     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1629     if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
1630         portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
1631         portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
1632
1633         /* the port name is expected to be null-terminated */
1634         ASSERT(portName[portNameLen - 1] == '\0');
1635
1636         vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
1637     } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
1638         portNumber = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
1639
1640         vport = OvsFindVportByPortNo(gOvsSwitchContext, portNumber);
1641     } else {
1642         nlError = NL_ERROR_INVAL;
1643         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1644         goto Cleanup;
1645     }
1646
1647     if (!vport) {
1648         nlError = NL_ERROR_NODEV;
1649         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1650         goto Cleanup;
1651     }
1652
1653     status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
1654                                    usrParamsCtx->outputLength,
1655                                    gOvsSwitchContext->dpNo);
1656     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1657
1658     *replyLen = msgOut->nlMsg.nlmsgLen;
1659
1660 Cleanup:
1661     if (nlError != NL_ERROR_SUCCESS) {
1662         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1663             usrParamsCtx->outputBuffer;
1664
1665         BuildErrorMsg(msgIn, msgError, nlError);
1666         *replyLen = msgError->nlMsg.nlmsgLen;
1667     }
1668
1669     return STATUS_SUCCESS;
1670 }
1671
1672 /*
1673  * --------------------------------------------------------------------------
1674  *  Handler for the get vport command. The function handles the initial call to
1675  *  setup the dump state, as well as subsequent calls to continue dumping data.
1676  * --------------------------------------------------------------------------
1677 */
1678 static NTSTATUS
1679 OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1680                       UINT32 *replyLen)
1681 {
1682     *replyLen = 0;
1683
1684     switch (usrParamsCtx->devOp)
1685     {
1686     case OVS_WRITE_DEV_OP:
1687         return OvsSetupDumpStart(usrParamsCtx);
1688
1689     case OVS_READ_DEV_OP:
1690         return OvsGetVportDumpNext(usrParamsCtx, replyLen);
1691
1692     case OVS_TRANSACTION_DEV_OP:
1693         return OvsGetVport(usrParamsCtx, replyLen);
1694
1695     default:
1696         return STATUS_INVALID_DEVICE_REQUEST;
1697     }
1698
1699 }
1700
1701
1702
1703 static UINT32
1704 OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext)
1705 {
1706     /* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
1707     for (ULONG i = OVS_DPPORT_NUMBER_LOCAL + 1; i < MAXUINT16; ++i) {
1708         POVS_VPORT_ENTRY vport;
1709
1710         vport = OvsFindVportByPortNo(switchContext, i);
1711         if (!vport) {
1712             return i;
1713         }
1714     }
1715
1716     return OVS_DPPORT_NUMBER_INVALID;
1717 }
1718
1719 /*
1720  * --------------------------------------------------------------------------
1721  *  Command Handler for 'OVS_VPORT_CMD_NEW'.
1722  * --------------------------------------------------------------------------
1723  */
1724 static NTSTATUS
1725 OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1726                       UINT32 *replyLen)
1727 {
1728     NDIS_STATUS status = STATUS_SUCCESS;
1729     LOCK_STATE_EX lockState;
1730
1731     NL_ERROR nlError = NL_ERROR_SUCCESS;
1732     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1733     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1734     POVS_VPORT_ENTRY vport = NULL;
1735     PCHAR portName;
1736     ULONG portNameLen;
1737     UINT32 portType;
1738     UINT32 hash;
1739
1740     static const NL_POLICY ovsVportPolicy[] = {
1741         [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
1742         [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
1743         [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
1744                                   .optional = FALSE},
1745         [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
1746                                         .optional = FALSE },
1747         [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
1748     };
1749
1750     PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
1751
1752     /* input buffer has been validated while validating write dev op. */
1753     ASSERT(usrParamsCtx->inputBuffer != NULL);
1754
1755     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1756         return STATUS_INVALID_BUFFER_SIZE;
1757     }
1758
1759     if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1760         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1761         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1762         ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
1763         return STATUS_INVALID_PARAMETER;
1764     }
1765
1766     OvsAcquireCtrlLock();
1767     if (!gOvsSwitchContext) {
1768         OvsReleaseCtrlLock();
1769         return STATUS_INVALID_PARAMETER;
1770     }
1771     OvsReleaseCtrlLock();
1772
1773     portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
1774     portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
1775     portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
1776
1777     /* we are expecting null terminated strings to be passed */
1778     ASSERT(portName[portNameLen - 1] == '\0');
1779
1780     NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
1781
1782     vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
1783     if (vport) {
1784         nlError = NL_ERROR_EXIST;
1785         goto Cleanup;
1786     }
1787
1788     if (portType == OVS_VPORT_TYPE_INTERNAL) {
1789         vport = gOvsSwitchContext->internalVport;
1790     } else if (portType == OVS_VPORT_TYPE_NETDEV) {
1791         if (!strcmp(portName, "external")) {
1792             vport = gOvsSwitchContext->externalVport;
1793         } else {
1794             vport = OvsFindVportByHvName(gOvsSwitchContext, portName);
1795         }
1796     } else {
1797         /* XXX: change when other tunneling ports are added */
1798         ASSERT(portType == OVS_VPORT_TYPE_VXLAN);
1799
1800         if (gOvsSwitchContext->vxlanVport) {
1801             nlError = NL_ERROR_EXIST;
1802             goto Cleanup;
1803         }
1804
1805         vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
1806         if (vport == NULL) {
1807             nlError = NL_ERROR_NOMEM;
1808             goto Cleanup;
1809         }
1810
1811         vport->ovsState = OVS_STATE_PORT_CREATED;
1812
1813         /*
1814          * XXX: when we allow configuring the vxlan udp port, we should read
1815          * this from vport->options instead!
1816         */
1817         nlError = OvsInitVxlanTunnel(vport, VXLAN_UDP_PORT);
1818         if (nlError != NL_ERROR_SUCCESS) {
1819             goto Cleanup;
1820         }
1821     }
1822
1823     if (!vport) {
1824         nlError = NL_ERROR_INVAL;
1825         goto Cleanup;
1826     }
1827
1828     if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
1829         nlError = NL_ERROR_EXIST;
1830         goto Cleanup;
1831     }
1832
1833     /* Fill the data in vport */
1834     vport->ovsType = portType;
1835
1836     if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
1837         /*
1838         * XXX: when we implement the limit for ovs port number to be
1839         * MAXUINT16, we'll need to check the port number received from the
1840         * userspace.
1841         */
1842         vport->portNo = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
1843     } else {
1844         vport->portNo = OvsComputeVportNo(gOvsSwitchContext);
1845         if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
1846             nlError = NL_ERROR_NOMEM;
1847             goto Cleanup;
1848         }
1849     }
1850
1851     /* The ovs port name must be uninitialized. */
1852     ASSERT(vport->ovsName[0] == '\0');
1853     ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
1854
1855     RtlCopyMemory(vport->ovsName, portName, portNameLen);
1856
1857     /* if we don't have options, then vport->portOptions will be NULL */
1858     vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
1859
1860     /*
1861     * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1862     * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1863     * it means we have an array of pids, instead of a single pid.
1864     * ATM we assume we have one pid only.
1865     */
1866     vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
1867
1868     if (vport->ovsType == OVS_VPORT_TYPE_VXLAN) {
1869         gOvsSwitchContext->vxlanVport = vport;
1870     } else if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
1871         gOvsSwitchContext->internalVport = vport;
1872         gOvsSwitchContext->internalPortId = vport->portId;
1873     } else if (vport->ovsType == OVS_VPORT_TYPE_NETDEV &&
1874                vport->isExternal) {
1875         gOvsSwitchContext->externalVport = vport;
1876         gOvsSwitchContext->externalPortId = vport->portId;
1877     }
1878
1879     /*
1880      * insert the port into the hash array of ports: by port number and ovs
1881      * and ovs (datapath) port name.
1882      * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
1883      * portNo is stored in 2 bytes only (max port number = MAXUINT16).
1884     */
1885     hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
1886     InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
1887                    &vport->portNoLink);
1888
1889     hash = OvsJhashBytes(vport->ovsName, portNameLen, OVS_HASH_BASIS);
1890     InsertHeadList(&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
1891                    &vport->ovsNameLink);
1892
1893     status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
1894                                    usrParamsCtx->outputLength,
1895                                    gOvsSwitchContext->dpNo);
1896
1897     *replyLen = msgOut->nlMsg.nlmsgLen;
1898
1899 Cleanup:
1900     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1901
1902     if (nlError != NL_ERROR_SUCCESS) {
1903         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1904             usrParamsCtx->outputBuffer;
1905
1906         if (vport && vport->ovsType == OVS_VPORT_TYPE_VXLAN) {
1907             OvsRemoveAndDeleteVport(gOvsSwitchContext, vport);
1908         }
1909
1910         BuildErrorMsg(msgIn, msgError, nlError);
1911         *replyLen = msgError->nlMsg.nlmsgLen;
1912     }
1913
1914     return STATUS_SUCCESS;
1915 }
1916
1917
1918 /*
1919  * --------------------------------------------------------------------------
1920  *  Command Handler for 'OVS_VPORT_CMD_SET'.
1921  * --------------------------------------------------------------------------
1922  */
1923 static NTSTATUS
1924 OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1925                       UINT32 *replyLen)
1926 {
1927     NDIS_STATUS status = STATUS_SUCCESS;
1928     LOCK_STATE_EX lockState;
1929
1930     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1931     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1932     POVS_VPORT_ENTRY vport = NULL;
1933     NL_ERROR nlError = NL_ERROR_SUCCESS;
1934
1935     static const NL_POLICY ovsVportPolicy[] = {
1936         [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
1937         [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = TRUE },
1938         [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
1939                                   .optional = TRUE },
1940         [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
1941                                         .optional = TRUE },
1942         [OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
1943                                    .minLen = sizeof(OVS_VPORT_FULL_STATS),
1944                                    .maxLen = sizeof(OVS_VPORT_FULL_STATS),
1945                                    .optional = TRUE },
1946         [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
1947     };
1948     PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
1949
1950     ASSERT(usrParamsCtx->inputBuffer != NULL);
1951
1952     if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1953         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1954         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1955         ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
1956         return STATUS_INVALID_PARAMETER;
1957     }
1958
1959     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1960         return STATUS_NDIS_INVALID_LENGTH;
1961     }
1962
1963     OvsAcquireCtrlLock();
1964     if (!gOvsSwitchContext) {
1965         OvsReleaseCtrlLock();
1966         return STATUS_INVALID_PARAMETER;
1967     }
1968
1969     NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
1970     if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
1971         PSTR portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
1972 #ifdef DBG
1973         UINT32 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
1974 #endif
1975         /* the port name is expected to be null-terminated */
1976         ASSERT(portName[portNameLen - 1] == '\0');
1977
1978         vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
1979     } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
1980         vport = OvsFindVportByPortNo(gOvsSwitchContext,
1981                     NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
1982     }
1983
1984     if (!vport) {
1985         nlError = NL_ERROR_NODEV;
1986         goto Cleanup;
1987     }
1988
1989     /*
1990      * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1991      * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1992      * it means we have an array of pids, instead of a single pid.
1993      * Currently, we support only one pid.
1994      */
1995     if (vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]) {
1996         vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
1997     }
1998
1999     if (vportAttrs[OVS_VPORT_ATTR_TYPE]) {
2000         OVS_VPORT_TYPE type = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2001         if (type != vport->ovsType) {
2002             nlError = NL_ERROR_INVAL;
2003             goto Cleanup;
2004         }
2005     }
2006
2007     if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
2008         OVS_LOG_ERROR("Vport options not supported");
2009         nlError = NL_ERROR_NOTSUPP;
2010         goto Cleanup;
2011     }
2012
2013     status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2014                                    usrParamsCtx->outputLength,
2015                                    gOvsSwitchContext->dpNo);
2016
2017     *replyLen = msgOut->nlMsg.nlmsgLen;
2018
2019 Cleanup:
2020     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2021     OvsReleaseCtrlLock();
2022
2023     if (nlError != NL_ERROR_SUCCESS) {
2024         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2025             usrParamsCtx->outputBuffer;
2026
2027         BuildErrorMsg(msgIn, msgError, nlError);
2028         *replyLen = msgError->nlMsg.nlmsgLen;
2029     }
2030
2031     return STATUS_SUCCESS;
2032 }
2033
2034 /*
2035  * --------------------------------------------------------------------------
2036  *  Command Handler for 'OVS_VPORT_CMD_DEL'.
2037  * --------------------------------------------------------------------------
2038  */
2039 static NTSTATUS
2040 OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2041                          UINT32 *replyLen)
2042 {
2043     NDIS_STATUS status = STATUS_SUCCESS;
2044     LOCK_STATE_EX lockState;
2045
2046     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2047     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2048     POVS_VPORT_ENTRY vport = NULL;
2049     NL_ERROR nlError = NL_ERROR_SUCCESS;
2050     PSTR portName = NULL;
2051     UINT32 portNameLen = 0;
2052
2053     static const NL_POLICY ovsVportPolicy[] = {
2054         [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2055         [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ, .optional = TRUE },
2056     };
2057     PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2058
2059     ASSERT(usrParamsCtx->inputBuffer != NULL);
2060
2061     if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2062         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2063         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2064         ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
2065         return STATUS_INVALID_PARAMETER;
2066     }
2067
2068     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
2069         return STATUS_NDIS_INVALID_LENGTH;
2070     }
2071
2072     OvsAcquireCtrlLock();
2073     if (!gOvsSwitchContext) {
2074         OvsReleaseCtrlLock();
2075         return STATUS_INVALID_PARAMETER;
2076     }
2077     OvsReleaseCtrlLock();
2078
2079     NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2080     if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2081         portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2082         portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2083
2084         /* the port name is expected to be null-terminated */
2085         ASSERT(portName[portNameLen - 1] == '\0');
2086
2087         vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2088     }
2089     else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2090         vport = OvsFindVportByPortNo(gOvsSwitchContext,
2091             NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2092     }
2093
2094     if (!vport) {
2095         nlError = NL_ERROR_NODEV;
2096         goto Cleanup;
2097     }
2098
2099     status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2100                                    usrParamsCtx->outputLength,
2101                                    gOvsSwitchContext->dpNo);
2102
2103     if (vport->hvDeleted || OvsIsTunnelVportType(vport->ovsType)) {
2104         /*
2105          * The associated hyper-v switch port is not in created state, or,
2106          * there is no hyper-v switch port counterpart (for logical ports).
2107          * This means that this datapath port is not mapped to a living
2108          * hyper-v switc hport. We can destroy and remove the vport from the
2109          * list.
2110         */
2111         OvsRemoveAndDeleteVport(gOvsSwitchContext, vport);
2112     } else {
2113         /* The associated hyper-v switch port is in the created state, and the
2114          * datapath port is mapped to a living hyper-v switch port. We cannot
2115          * destroy the vport and cannot remove it from the list of vports.
2116          * Instead, we mark the datapath (ovs) part of the vport as
2117          * "not created", i.e. we set vport->portNo = OVS_PORT_NUMBER_INVALID.
2118         */
2119         RemoveEntryList(&vport->ovsNameLink);
2120         RemoveEntryList(&vport->portNoLink);
2121         vport->portNo = OVS_DPPORT_NUMBER_INVALID;
2122         vport->ovsName[0] = '\0';
2123     }
2124
2125     *replyLen = msgOut->nlMsg.nlmsgLen;
2126
2127 Cleanup:
2128     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2129
2130     if (nlError != NL_ERROR_SUCCESS) {
2131         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2132             usrParamsCtx->outputBuffer;
2133
2134         BuildErrorMsg(msgIn, msgError, nlError);
2135         *replyLen = msgError->nlMsg.nlmsgLen;
2136     }
2137
2138     return STATUS_SUCCESS;
2139 }
2140
2141
2142 /*
2143  * --------------------------------------------------------------------------
2144  *  Utility function to map the output buffer in an IRP. The buffer is assumed
2145  *  to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
2146  * --------------------------------------------------------------------------
2147  */
2148 static NTSTATUS
2149 MapIrpOutputBuffer(PIRP irp,
2150                    UINT32 bufferLength,
2151                    UINT32 requiredLength,
2152                    PVOID *buffer)
2153 {
2154     ASSERT(irp);
2155     ASSERT(buffer);
2156     ASSERT(bufferLength);
2157     ASSERT(requiredLength);
2158     if (!buffer || !irp || bufferLength == 0 || requiredLength == 0) {
2159         return STATUS_INVALID_PARAMETER;
2160     }
2161
2162     if (bufferLength < requiredLength) {
2163         return STATUS_NDIS_INVALID_LENGTH;
2164     }
2165     if (irp->MdlAddress == NULL) {
2166         return STATUS_INVALID_PARAMETER;
2167     }
2168     *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
2169                                            NormalPagePriority);
2170     if (*buffer == NULL) {
2171         return STATUS_INSUFFICIENT_RESOURCES;
2172     }
2173
2174     return STATUS_SUCCESS;
2175 }
2176
2177 /*
2178  * --------------------------------------------------------------------------
2179  * Utility function to fill up information about the state of a port in a reply
2180  * to* userspace.
2181  * Assumes that 'gOvsCtrlLock' lock is acquired.
2182  * --------------------------------------------------------------------------
2183  */
2184 static NTSTATUS
2185 OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2186                 POVS_EVENT_ENTRY eventEntry,
2187                 PNL_BUFFER nlBuf)
2188 {
2189     NTSTATUS status;
2190     BOOLEAN rc;
2191     OVS_MESSAGE msgOutTmp;
2192     PNL_MSG_HDR nlMsg;
2193     POVS_VPORT_ENTRY vport;
2194
2195     ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && nlBuf->bufRemLen >= sizeof msgOutTmp);
2196
2197     msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_VPORT_FAMILY_ID;
2198     msgOutTmp.nlMsg.nlmsgFlags = 0;  /* XXX: ? */
2199
2200     /* driver intiated messages should have zerp seq number*/
2201     msgOutTmp.nlMsg.nlmsgSeq = 0;
2202     msgOutTmp.nlMsg.nlmsgPid = usrParamsCtx->ovsInstance->pid;
2203
2204     msgOutTmp.genlMsg.version = nlVportFamilyOps.version;
2205     msgOutTmp.genlMsg.reserved = 0;
2206
2207     /* we don't have netdev yet, treat link up/down a adding/removing a port*/
2208     if (eventEntry->status & (OVS_EVENT_LINK_UP | OVS_EVENT_CONNECT)) {
2209         msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_NEW;
2210     } else if (eventEntry->status &
2211              (OVS_EVENT_LINK_DOWN | OVS_EVENT_DISCONNECT)) {
2212         msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_DEL;
2213     } else {
2214         ASSERT(FALSE);
2215         return STATUS_UNSUCCESSFUL;
2216     }
2217     msgOutTmp.ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
2218
2219     rc = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
2220     if (!rc) {
2221         status = STATUS_INVALID_BUFFER_SIZE;
2222         goto cleanup;
2223     }
2224
2225     vport = OvsFindVportByPortNo(gOvsSwitchContext, eventEntry->portNo);
2226     if (!vport) {
2227         status = STATUS_DEVICE_DOES_NOT_EXIST;
2228         goto cleanup;
2229     }
2230
2231     rc = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) ||
2232          NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, vport->ovsType) ||
2233          NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, vport->ovsName);
2234     if (!rc) {
2235         status = STATUS_INVALID_BUFFER_SIZE;
2236         goto cleanup;
2237     }
2238
2239     /* XXXX Should we add the port stats attributes?*/
2240     nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
2241     nlMsg->nlmsgLen = NlBufSize(nlBuf);
2242     status = STATUS_SUCCESS;
2243
2244 cleanup:
2245     return status;
2246 }
2247
2248
2249 /*
2250  * --------------------------------------------------------------------------
2251  * Handler for reading events from the driver event queue. This handler is
2252  * executed when user modes issues a socket receive on a socket assocaited
2253  * with the MC group for events.
2254  * XXX user mode should read multiple events in one system call
2255  * --------------------------------------------------------------------------
2256  */
2257 static NTSTATUS
2258 OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2259                        UINT32 *replyLen)
2260 {
2261 #ifdef DBG
2262     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2263     POVS_OPEN_INSTANCE instance =
2264         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
2265 #endif
2266     NL_BUFFER nlBuf;
2267     NTSTATUS status;
2268     OVS_EVENT_ENTRY eventEntry;
2269
2270     ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
2271
2272     /* Should never read events with a dump socket */
2273     ASSERT(instance->dumpState.ovsMsg == NULL);
2274
2275     /* Must have an event queue */
2276     ASSERT(instance->eventQueue != NULL);
2277
2278     /* Output buffer has been validated while validating read dev op. */
2279     ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2280
2281     NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
2282
2283     OvsAcquireCtrlLock();
2284     if (!gOvsSwitchContext) {
2285         status = STATUS_SUCCESS;
2286         goto cleanup;
2287     }
2288
2289     /* remove an event entry from the event queue */
2290     status = OvsRemoveEventEntry(usrParamsCtx->ovsInstance, &eventEntry);
2291     if (status != STATUS_SUCCESS) {
2292         goto cleanup;
2293     }
2294
2295     status = OvsPortFillInfo(usrParamsCtx, &eventEntry, &nlBuf);
2296     if (status == NDIS_STATUS_SUCCESS) {
2297         *replyLen = NlBufSize(&nlBuf);
2298     }
2299
2300 cleanup:
2301     OvsReleaseCtrlLock();
2302     return status;
2303 }
2304
2305 /*
2306  * --------------------------------------------------------------------------
2307  * Handler for reading missed pacckets from the driver event queue. This
2308  * handler is executed when user modes issues a socket receive on a socket
2309  * --------------------------------------------------------------------------
2310  */
2311 static NTSTATUS
2312 OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2313                        UINT32 *replyLen)
2314 {
2315 #ifdef DBG
2316     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2317 #endif
2318     POVS_OPEN_INSTANCE instance =
2319         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
2320     NTSTATUS status;
2321
2322     ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
2323
2324     /* Should never read events with a dump socket */
2325     ASSERT(instance->dumpState.ovsMsg == NULL);
2326
2327     /* Must have an packet queue */
2328     ASSERT(instance->packetQueue != NULL);
2329
2330     /* Output buffer has been validated while validating read dev op. */
2331     ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2332
2333     OvsAcquireCtrlLock();
2334     if (!gOvsSwitchContext) {
2335         status = STATUS_SUCCESS;
2336         OvsReleaseCtrlLock();
2337         return status;
2338     }
2339     OvsReleaseCtrlLock();
2340
2341     /* Read a packet from the instance queue */
2342     status = OvsReadDpIoctl(instance->fileObject, usrParamsCtx->outputBuffer,
2343                             usrParamsCtx->outputLength, replyLen);
2344     return status;
2345 }
2346 #endif /* OVS_USE_NL_INTERFACE */