datapath-windows: Fix subscribe/unsubscribe packets
[cascardo/ovs.git] / datapath-windows / ovsext / User.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  * OvsUser.c
19  *      Manage packet queue for packet miss for userAction.
20  */
21
22
23 #include "precomp.h"
24
25 #include "Switch.h"
26 #include "Vport.h"
27 #include "Event.h"
28 #include "User.h"
29 #include "Datapath.h"
30 #include "PacketIO.h"
31 #include "Checksum.h"
32 #include "NetProto.h"
33 #include "Flow.h"
34 #include "TunnelIntf.h"
35 #include "Jhash.h"
36
37 #ifdef OVS_DBG_MOD
38 #undef OVS_DBG_MOD
39 #endif
40 #define OVS_DBG_MOD OVS_DBG_USER
41 #include "Debug.h"
42
43 POVS_PACKET_QUEUE_ELEM OvsGetNextPacket(POVS_OPEN_INSTANCE instance);
44 extern PNDIS_SPIN_LOCK gOvsCtrlLock;
45 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
46 OVS_USER_STATS ovsUserStats;
47
48 static VOID _MapNlAttrToOvsPktExec(PNL_ATTR *nlAttrs, PNL_ATTR *keyAttrs,
49                                    OvsPacketExecute  *execute);
50 extern NL_POLICY nlFlowKeyPolicy[];
51 extern UINT32 nlFlowKeyPolicyLen;
52
53 static __inline VOID
54 OvsAcquirePidHashLock()
55 {
56     NdisAcquireSpinLock(&(gOvsSwitchContext->pidHashLock));
57 }
58
59 static __inline VOID
60 OvsReleasePidHashLock()
61 {
62     NdisReleaseSpinLock(&(gOvsSwitchContext->pidHashLock));
63 }
64
65
66 static VOID
67 OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue,
68                     POVS_OPEN_INSTANCE instance)
69 {
70     PLIST_ENTRY link, next;
71     LIST_ENTRY tmp;
72     POVS_PACKET_QUEUE_ELEM elem;
73
74     InitializeListHead(&tmp);
75     NdisAcquireSpinLock(&queue->queueLock);
76     if (queue->instance != instance) {
77         NdisReleaseSpinLock(&queue->queueLock);
78         return;
79     }
80
81     if (queue->numPackets) {
82         OvsAppendList(&tmp, &queue->packetList);
83         queue->numPackets = 0;
84     }
85     NdisReleaseSpinLock(&queue->queueLock);
86     LIST_FORALL_SAFE(&tmp, link, next) {
87         RemoveEntryList(link);
88         elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
89         OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
90     }
91 }
92
93 VOID
94 OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance)
95 {
96     POVS_USER_PACKET_QUEUE queue;
97     POVS_PACKET_QUEUE_ELEM elem;
98     PLIST_ENTRY link, next;
99     LIST_ENTRY tmp;
100     PIRP irp = NULL;
101
102     ASSERT(instance);
103     InitializeListHead(&tmp);
104     queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
105     if (queue) {
106         PDRIVER_CANCEL cancelRoutine;
107         NdisAcquireSpinLock(&queue->queueLock);
108         ASSERT(queue->instance == instance);
109         /* XXX Should not happen */
110         if (queue->instance != instance) {
111             NdisReleaseSpinLock(&queue->queueLock);
112             NdisFreeSpinLock(&queue->queueLock);
113             return;
114         }
115
116         if (queue->numPackets) {
117             OvsAppendList(&tmp, &queue->packetList);
118             queue->numPackets = 0;
119         }
120         queue->instance = NULL;
121         instance->packetQueue = NULL;
122         irp = queue->pendingIrp;
123         queue->pendingIrp = NULL;
124         if (irp) {
125             cancelRoutine = IoSetCancelRoutine(irp, NULL);
126             if (cancelRoutine == NULL) {
127                 irp = NULL;
128             }
129         }
130         NdisReleaseSpinLock(&queue->queueLock);
131         NdisFreeSpinLock(&queue->queueLock);
132     }
133     LIST_FORALL_SAFE(&tmp, link, next) {
134         RemoveEntryList(link);
135         elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
136         OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
137     }
138     if (irp) {
139         OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
140     }
141     if (queue) {
142         OvsFreeMemoryWithTag(queue, OVS_USER_POOL_TAG);
143     }
144
145     /* Verify if gOvsSwitchContext exists. */
146     if (gOvsSwitchContext) {
147         /* Remove the instance from pidHashArray */
148         OvsAcquirePidHashLock();
149         OvsDelPidInstance(gOvsSwitchContext, instance->pid);
150         OvsReleasePidHashLock();
151     }
152 }
153
154 NTSTATUS
155 OvsSubscribeDpIoctl(PVOID instanceP,
156                     UINT32 pid,
157                     UINT8 join)
158 {
159     POVS_USER_PACKET_QUEUE queue;
160     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)instanceP;
161
162     if (instance->packetQueue && !join) {
163         /* unsubscribe */
164         OvsCleanupPacketQueue(instance);
165     } else if (instance->packetQueue == NULL && join) {
166         queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemoryWithTag(
167             sizeof *queue, OVS_USER_POOL_TAG);
168         if (queue == NULL) {
169             return STATUS_NO_MEMORY;
170         }
171         InitializeListHead(&(instance->pidLink));
172         instance->packetQueue = queue;
173         RtlZeroMemory(queue, sizeof (*queue));
174         NdisAllocateSpinLock(&queue->queueLock);
175         NdisAcquireSpinLock(&queue->queueLock);
176         InitializeListHead(&queue->packetList);
177         queue->pid = pid;
178         queue->instance = instance;
179         instance->packetQueue = queue;
180         NdisReleaseSpinLock(&queue->queueLock);
181
182         OvsAcquirePidHashLock();
183         /* Insert the instance to pidHashArray */
184         OvsAddPidInstance(gOvsSwitchContext, pid, instance);
185         OvsReleasePidHashLock();
186
187     } else {
188         /* user mode should call only once for subscribe */
189         return STATUS_INVALID_PARAMETER;
190     }
191
192     return STATUS_SUCCESS;
193 }
194
195
196 NTSTATUS
197 OvsReadDpIoctl(PFILE_OBJECT fileObject,
198                PVOID outputBuffer,
199                UINT32 outputLength,
200                UINT32 *replyLen)
201 {
202     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
203     POVS_PACKET_QUEUE_ELEM elem;
204     UINT32 len;
205
206 #define TCP_CSUM_OFFSET  16
207 #define UDP_CSUM_OFFSET  6
208     ASSERT(instance);
209
210     if (instance->packetQueue == NULL) {
211         return STATUS_INVALID_PARAMETER;
212     }
213     if (outputLength < (sizeof (OVS_PACKET_INFO) + OVS_MIN_PACKET_SIZE)) {
214         return STATUS_BUFFER_TOO_SMALL;
215     }
216
217     elem = OvsGetNextPacket(instance);
218     if (elem) {
219         /*
220          * XXX revisit this later
221          */
222         len = elem->packet.totalLen > outputLength ? outputLength :
223                  elem->packet.totalLen;
224
225         if ((elem->hdrInfo.tcpCsumNeeded || elem->hdrInfo.udpCsumNeeded) &&
226             len == elem->packet.totalLen) {
227             UINT16 sum, *ptr;
228             UINT16 size = (UINT16)(elem->packet.payload - elem->packet.data +
229                                   elem->hdrInfo.l4Offset);
230             RtlCopyMemory(outputBuffer, &elem->packet.data, size);
231             ASSERT(len - size >= elem->hdrInfo.l4PayLoad);
232             sum = CopyAndCalculateChecksum((UINT8 *)outputBuffer + size,
233                                            (UINT8 *)&elem->packet.data + size,
234                                            elem->hdrInfo.l4PayLoad, 0);
235             ptr =(UINT16 *)((UINT8 *)outputBuffer + size +
236                             (elem->hdrInfo.tcpCsumNeeded ?
237                              TCP_CSUM_OFFSET : UDP_CSUM_OFFSET));
238             *ptr = sum;
239             ovsUserStats.l4Csum++;
240         } else {
241             RtlCopyMemory(outputBuffer, &elem->packet.data, len);
242         }
243
244         *replyLen = len;
245         OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
246     }
247     return STATUS_SUCCESS;
248 }
249
250 /* Helper function to allocate a Forwarding Context for an NBL */
251 NTSTATUS
252 OvsAllocateForwardingContextForNBL(POVS_SWITCH_CONTEXT switchContext,
253                                    PNET_BUFFER_LIST nbl)
254 {
255     return switchContext->NdisSwitchHandlers.
256         AllocateNetBufferListForwardingContext(
257             switchContext->NdisSwitchContext, nbl);
258 }
259
260 /*
261  *----------------------------------------------------------------------------
262  *  OvsNlExecuteCmdHandler --
263  *    Handler for OVS_PACKET_CMD_EXECUTE command.
264  *----------------------------------------------------------------------------
265  */
266 NTSTATUS
267 OvsNlExecuteCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
268                        UINT32 *replyLen)
269 {
270     NTSTATUS status = STATUS_SUCCESS;
271     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
272     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
273     PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
274     PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
275     POVS_HDR ovsHdr = &(msgIn->ovsHdr);
276
277     PNL_ATTR nlAttrs[__OVS_PACKET_ATTR_MAX];
278     PNL_ATTR keyAttrs[__OVS_KEY_ATTR_MAX] = {NULL};
279
280     UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN;
281     UINT32 keyAttrOffset = 0;
282     OvsPacketExecute execute;
283     NL_ERROR nlError = NL_ERROR_SUCCESS;
284     NL_BUFFER nlBuf;
285
286     static const NL_POLICY nlPktExecPolicy[] = {
287         [OVS_PACKET_ATTR_PACKET] = {.type = NL_A_UNSPEC, .optional = FALSE},
288         [OVS_PACKET_ATTR_KEY] = {.type = NL_A_UNSPEC, .optional = FALSE},
289         [OVS_PACKET_ATTR_ACTIONS] = {.type = NL_A_UNSPEC, .optional = FALSE},
290         [OVS_PACKET_ATTR_USERDATA] = {.type = NL_A_UNSPEC, .optional = TRUE},
291         [OVS_PACKET_ATTR_EGRESS_TUN_KEY] = {.type = NL_A_UNSPEC,
292                                             .optional = TRUE}
293     };
294
295     RtlZeroMemory(&execute, sizeof(OvsPacketExecute));
296
297     /* Get all the top level Flow attributes */
298     if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrsLen(nlMsgHdr),
299                      nlPktExecPolicy, ARRAY_SIZE(nlPktExecPolicy),
300                      nlAttrs, ARRAY_SIZE(nlAttrs)))
301                      != TRUE) {
302         OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
303                        nlMsgHdr);
304         status = STATUS_UNSUCCESSFUL;
305         goto done;
306     }
307
308     keyAttrOffset = (UINT32)((PCHAR)nlAttrs[OVS_PACKET_ATTR_KEY] -
309                     (PCHAR)nlMsgHdr);
310
311     /* Get flow keys attributes */
312     if ((NlAttrParseNested(nlMsgHdr, keyAttrOffset,
313                            NlAttrLen(nlAttrs[OVS_PACKET_ATTR_KEY]),
314                            nlFlowKeyPolicy, nlFlowKeyPolicyLen,
315                            keyAttrs, ARRAY_SIZE(keyAttrs))) != TRUE) {
316         OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p", nlMsgHdr);
317         status = STATUS_UNSUCCESSFUL;
318         goto done;
319     }
320
321     execute.dpNo = ovsHdr->dp_ifindex;
322
323     _MapNlAttrToOvsPktExec(nlAttrs, keyAttrs, &execute);
324
325     status = OvsExecuteDpIoctl(&execute);
326
327     /* Default reply that we want to send */
328     if (status == STATUS_SUCCESS) {
329         BOOLEAN ok;
330
331         NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
332                   usrParamsCtx->outputLength);
333
334         /* Prepare nl Msg headers */
335         ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
336                  nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
337                  genlMsgHdr->cmd, OVS_PACKET_VERSION,
338                  ovsHdr->dp_ifindex);
339
340         if (ok) {
341             *replyLen = msgOut->nlMsg.nlmsgLen;
342         } else {
343             status = STATUS_INVALID_BUFFER_SIZE;
344         }
345     } else {
346         /* Map NTSTATUS to NL_ERROR */
347         nlError = NlMapStatusToNlErr(status);
348
349         /* As of now there are no transactional errors in the implementation.
350          * Once we have them then we need to map status to correct
351          * nlError value, so that below mentioned code gets hit. */
352         if ((nlError != NL_ERROR_SUCCESS) &&
353             (usrParamsCtx->outputBuffer)) {
354
355             POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
356                                            usrParamsCtx->outputBuffer;
357             NlBuildErrorMsg(msgIn, msgError, nlError);
358             *replyLen = msgError->nlMsg.nlmsgLen;
359             status = STATUS_SUCCESS;
360             goto done;
361         }
362     }
363
364 done:
365     return status;
366 }
367
368 /*
369  *----------------------------------------------------------------------------
370  *  _MapNlAttrToOvsPktExec --
371  *    Maps input Netlink attributes to OvsPacketExecute.
372  *----------------------------------------------------------------------------
373  */
374 static VOID
375 _MapNlAttrToOvsPktExec(PNL_ATTR *nlAttrs, PNL_ATTR *keyAttrs,
376                        OvsPacketExecute *execute)
377 {
378     execute->packetBuf = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_PACKET]);
379     execute->packetLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_PACKET]);
380
381     execute->actions = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
382     execute->actionsLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
383
384     execute->inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
385 }
386
387 NTSTATUS
388 OvsExecuteDpIoctl(OvsPacketExecute *execute)
389 {
390     NTSTATUS                    status = STATUS_SUCCESS;
391     NTSTATUS                    ndisStatus;
392     LOCK_STATE_EX               lockState;
393     PNET_BUFFER_LIST pNbl;
394     PNL_ATTR actions;
395     PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
396     OvsFlowKey key;
397     OVS_PACKET_HDR_INFO layers;
398     POVS_VPORT_ENTRY vport;
399
400     if (execute->packetLen == 0) {
401         status = STATUS_INVALID_PARAMETER;
402         goto exit;
403     }
404
405     actions = execute->actions;
406
407     ASSERT(actions);
408
409     /*
410      * Allocate the NBL, copy the data from the userspace buffer. Allocate
411      * also, the forwarding context for the packet.
412      */
413     pNbl = OvsAllocateNBLFromBuffer(gOvsSwitchContext, execute->packetBuf,
414                                     execute->packetLen);
415     if (pNbl == NULL) {
416         status = STATUS_NO_MEMORY;
417         goto exit;
418     }
419
420     fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);
421     vport = OvsFindVportByPortNo(gOvsSwitchContext, execute->inPort);
422     if (vport) {
423         fwdDetail->SourcePortId = vport->portId;
424         fwdDetail->SourceNicIndex = vport->nicIndex;
425     } else {
426         fwdDetail->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
427         fwdDetail->SourceNicIndex = 0;
428     }
429     // XXX: Figure out if any of the other members of fwdDetail need to be set.
430
431     ndisStatus = OvsExtractFlow(pNbl, fwdDetail->SourcePortId, &key, &layers,
432                                 NULL);
433     if (ndisStatus == NDIS_STATUS_SUCCESS) {
434         NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
435         ndisStatus = OvsActionsExecute(gOvsSwitchContext, NULL, pNbl,
436                                        vport ? vport->portNo :
437                                                OVS_DPPORT_NUMBER_INVALID,
438                                        NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP,
439                                        &key, NULL, &layers, actions,
440                                        execute->actionsLen);
441         pNbl = NULL;
442         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
443     }
444     if (ndisStatus != NDIS_STATUS_SUCCESS) {
445         if (ndisStatus == NDIS_STATUS_NOT_SUPPORTED) {
446             status = STATUS_NOT_SUPPORTED;
447         } else {
448             status = STATUS_UNSUCCESSFUL;
449         }
450     }
451
452     if (pNbl) {
453         OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE);
454     }
455 exit:
456     return status;
457 }
458
459
460 NTSTATUS
461 OvsPurgeDpIoctl(PFILE_OBJECT fileObject)
462 {
463     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
464     POVS_USER_PACKET_QUEUE queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
465
466     if (queue == NULL) {
467         return STATUS_INVALID_PARAMETER;
468     }
469     OvsPurgePacketQueue(queue, instance);
470     return STATUS_SUCCESS;
471 }
472
473 VOID
474 OvsCancelIrpDatapath(PDEVICE_OBJECT deviceObject,
475                      PIRP irp)
476 {
477     PIO_STACK_LOCATION irpSp;
478     PFILE_OBJECT fileObject;
479     POVS_OPEN_INSTANCE instance;
480     POVS_USER_PACKET_QUEUE queue = NULL;
481
482     UNREFERENCED_PARAMETER(deviceObject);
483
484     IoReleaseCancelSpinLock(irp->CancelIrql);
485     irpSp = IoGetCurrentIrpStackLocation(irp);
486     fileObject = irpSp->FileObject;
487
488     if (fileObject == NULL) {
489         goto done;
490     }
491     NdisAcquireSpinLock(gOvsCtrlLock);
492     instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
493     if (instance) {
494         queue = instance->packetQueue;
495     }
496     if (instance == NULL || queue == NULL) {
497         NdisReleaseSpinLock(gOvsCtrlLock);
498         goto done;
499     }
500     NdisReleaseSpinLock(gOvsCtrlLock);
501     NdisAcquireSpinLock(&queue->queueLock);
502     if (queue->pendingIrp == irp) {
503         queue->pendingIrp = NULL;
504     }
505     NdisReleaseSpinLock(&queue->queueLock);
506 done:
507     OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
508 }
509
510
511 NTSTATUS
512 OvsWaitDpIoctl(PIRP irp, PFILE_OBJECT fileObject)
513 {
514     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
515     POVS_USER_PACKET_QUEUE queue =
516                (POVS_USER_PACKET_QUEUE)instance->packetQueue;
517     NTSTATUS status = STATUS_SUCCESS;
518     BOOLEAN cancelled = FALSE;
519
520     if (queue == NULL) {
521         return STATUS_INVALID_PARAMETER;
522     }
523     NdisAcquireSpinLock(&queue->queueLock);
524     if (queue->instance != instance) {
525         NdisReleaseSpinLock(&queue->queueLock);
526         return STATUS_INVALID_PARAMETER;
527     }
528     if (queue->pendingIrp) {
529         NdisReleaseSpinLock(&queue->queueLock);
530         return STATUS_DEVICE_BUSY;
531     }
532     if (queue->numPackets == 0) {
533         PDRIVER_CANCEL cancelRoutine;
534         IoMarkIrpPending(irp);
535         IoSetCancelRoutine(irp, OvsCancelIrpDatapath);
536         if (irp->Cancel) {
537             cancelRoutine = IoSetCancelRoutine(irp, NULL);
538             if (cancelRoutine) {
539                 cancelled = TRUE;
540             }
541         } else {
542             queue->pendingIrp = irp;
543         }
544         status = STATUS_PENDING;
545     }
546     NdisReleaseSpinLock(&queue->queueLock);
547     if (cancelled) {
548         OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
549         OVS_LOG_INFO("Datapath IRP cancelled: %p", irp);
550     }
551     return status;
552 }
553
554
555 POVS_PACKET_QUEUE_ELEM
556 OvsGetNextPacket(POVS_OPEN_INSTANCE instance)
557 {
558     POVS_USER_PACKET_QUEUE queue;
559     PLIST_ENTRY link;
560     queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
561     if (queue == NULL) {
562         return NULL;
563     }
564     NdisAcquireSpinLock(&queue->queueLock);
565     if (queue->instance != instance || queue->numPackets == 0) {
566         NdisReleaseSpinLock(&queue->queueLock);
567         return NULL;
568     }
569     link = RemoveHeadList(&queue->packetList);
570     queue->numPackets--;
571     NdisReleaseSpinLock(&queue->queueLock);
572     return CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
573 }
574
575 /*
576  * ---------------------------------------------------------------------------
577  * Given a pid, returns the corresponding USER_PACKET_QUEUE.
578  * ---------------------------------------------------------------------------
579  */
580 POVS_USER_PACKET_QUEUE
581 OvsGetQueue(UINT32 pid)
582 {
583     POVS_OPEN_INSTANCE instance;
584     POVS_USER_PACKET_QUEUE ret = NULL;
585
586     instance = OvsGetPidInstance(gOvsSwitchContext, pid);
587
588     if (instance) {
589         ret = instance->packetQueue;
590     }
591
592     return ret;
593 }
594
595 /*
596  * ---------------------------------------------------------------------------
597  * Given a pid, returns the corresponding instance.
598  * pidHashLock must be acquired before calling this API.
599  * ---------------------------------------------------------------------------
600  */
601 POVS_OPEN_INSTANCE
602 OvsGetPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
603 {
604     POVS_OPEN_INSTANCE instance;
605     PLIST_ENTRY head, link;
606     UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
607                                 OVS_HASH_BASIS);
608     head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
609     LIST_FORALL(head, link) {
610         instance = CONTAINING_RECORD(link, OVS_OPEN_INSTANCE, pidLink);
611         if (instance->pid == pid) {
612             return instance;
613         }
614     }
615     return NULL;
616 }
617
618 /*
619  * ---------------------------------------------------------------------------
620  * Given a pid and an instance. This API adds instance to pidHashArray.
621  * pidHashLock must be acquired before calling this API.
622  * ---------------------------------------------------------------------------
623  */
624 VOID
625 OvsAddPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid,
626                   POVS_OPEN_INSTANCE instance)
627 {
628     PLIST_ENTRY head;
629     UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
630                                 OVS_HASH_BASIS);
631     head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
632     InsertHeadList(head, &(instance->pidLink));
633 }
634
635 /*
636  * ---------------------------------------------------------------------------
637  * Given a pid and an instance. This API removes instance from pidHashArray.
638  * pidHashLock must be acquired before calling this API.
639  * ---------------------------------------------------------------------------
640  */
641 VOID
642 OvsDelPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
643 {
644     POVS_OPEN_INSTANCE instance = OvsGetPidInstance(switchContext, pid);
645
646     if (instance) {
647         RemoveEntryList(&(instance->pidLink));
648     }
649 }
650
651 VOID
652 OvsQueuePackets(PLIST_ENTRY packetList,
653                 UINT32 numElems)
654 {
655     POVS_USER_PACKET_QUEUE upcallQueue = NULL;
656     POVS_PACKET_QUEUE_ELEM elem;
657     PLIST_ENTRY  link;
658     UINT32 num = 0;
659     LIST_ENTRY dropPackets;
660
661     OVS_LOG_LOUD("Enter: numELems: %u", numElems);
662
663     InitializeListHead(&dropPackets);
664
665     while (!IsListEmpty(packetList)) {
666         link = RemoveHeadList(packetList);
667         elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
668
669         ASSERT(elem);
670
671         OvsAcquirePidHashLock();
672
673         upcallQueue = OvsGetQueue(elem->upcallPid);
674         if (!upcallQueue) {
675             /* No upcall queue found, drop this packet. */
676             InsertTailList(&dropPackets, &elem->link);
677         } else {
678             NdisAcquireSpinLock(&upcallQueue->queueLock);
679
680             if (upcallQueue->instance == NULL) {
681                 InsertTailList(&dropPackets, &elem->link);
682             } else {
683                 InsertTailList(&upcallQueue->packetList, &elem->link);
684                 upcallQueue->numPackets++;
685                 if (upcallQueue->pendingIrp) {
686                     PIRP irp = upcallQueue->pendingIrp;
687                     PDRIVER_CANCEL cancelRoutine;
688                     upcallQueue->pendingIrp = NULL;
689                     cancelRoutine = IoSetCancelRoutine(irp, NULL);
690                     if (cancelRoutine != NULL) {
691                         OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
692                     }
693                 }
694             }
695             NdisReleaseSpinLock(&upcallQueue->queueLock);
696         }
697         OvsReleasePidHashLock();
698     }
699
700     while (!IsListEmpty(&dropPackets)) {
701         link = RemoveHeadList(&dropPackets);
702         elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
703         OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
704         num++;
705     }
706
707     OVS_LOG_LOUD("Exit: drop %u packets", num);
708 }
709
710 /*
711  *----------------------------------------------------------------------------
712  * OvsCreateAndAddPackets --
713  *
714  *  Create a packet and forwarded to user space.
715  *
716  *  This function would fragment packet if needed, and queue
717  *  each segment to user space.
718  *----------------------------------------------------------------------------
719  */
720 NTSTATUS
721 OvsCreateAndAddPackets(PVOID userData,
722                        UINT32 userDataLen,
723                        UINT32 cmd,
724                        POVS_VPORT_ENTRY vport,
725                        OvsFlowKey *key,
726                        PNET_BUFFER_LIST nbl,
727                        BOOLEAN isRecv,
728                        POVS_PACKET_HDR_INFO hdrInfo,
729                        POVS_SWITCH_CONTEXT switchContext,
730                        LIST_ENTRY *list,
731                        UINT32 *num)
732 {
733     POVS_PACKET_QUEUE_ELEM elem;
734     PNET_BUFFER_LIST newNbl = NULL;
735     PNET_BUFFER nb;
736
737     if (hdrInfo->isTcp) {
738         NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo;
739         UINT32 packetLength;
740
741         tsoInfo.Value = NET_BUFFER_LIST_INFO(nbl, TcpLargeSendNetBufferListInfo);
742         nb = NET_BUFFER_LIST_FIRST_NB(nbl);
743         packetLength = NET_BUFFER_DATA_LENGTH(nb);
744
745         OVS_LOG_TRACE("MSS %u packet len %u",
746                 tsoInfo.LsoV1Transmit.MSS, packetLength);
747         if (tsoInfo.LsoV1Transmit.MSS) {
748             OVS_LOG_TRACE("l4Offset %d", hdrInfo->l4Offset);
749             newNbl = OvsTcpSegmentNBL(switchContext, nbl, hdrInfo,
750                     tsoInfo.LsoV1Transmit.MSS , 0);
751             if (newNbl == NULL) {
752                 return NDIS_STATUS_FAILURE;
753             }
754             nbl = newNbl;
755         }
756     }
757
758     nb = NET_BUFFER_LIST_FIRST_NB(nbl);
759     while (nb) {
760         elem = OvsCreateQueueNlPacket(userData, userDataLen,
761                                     cmd, vport, key, nbl, nb,
762                                     isRecv, hdrInfo);
763         if (elem) {
764             InsertTailList(list, &elem->link);
765             (*num)++;
766         }
767         nb = NET_BUFFER_NEXT_NB(nb);
768     }
769     if (newNbl) {
770         OvsCompleteNBL(switchContext, newNbl, TRUE);
771     }
772     return NDIS_STATUS_SUCCESS;
773 }
774
775 static __inline UINT32
776 OvsGetUpcallMsgSize(PVOID userData,
777                     UINT32 userDataLen,
778                     OvsIPv4TunnelKey *tunnelKey,
779                     UINT32 payload)
780 {
781     UINT32 size = NLMSG_ALIGN(sizeof(struct ovs_header)) +
782                   NlAttrSize(payload) +
783                   NlAttrSize(OvsFlowKeyAttrSize());
784
785     /* OVS_PACKET_ATTR_USERDATA */
786     if (userData) {
787         size += NlAttrTotalSize(userDataLen);
788     }
789     /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
790     /* Is it included in the flow key attr XXX */
791     if (tunnelKey) {
792         size += NlAttrTotalSize(OvsTunKeyAttrSize());
793     }
794     return size;
795 }
796
797 /*
798  *----------------------------------------------------------------------------
799  * This function completes the IP Header csum. record the L4 payload offset and
800  * if there is a need to calculate the TCP or UDP csum. The actual csum will be
801  * caluculated simopultaneossly with the copy of the payload to the destination
802  * buffer when the packet is read.
803  *----------------------------------------------------------------------------
804  */
805 static VOID
806 OvsCompletePacketHeader(UINT8 *packet,
807                         BOOLEAN isRecv,
808                         NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo,
809                         POVS_PACKET_HDR_INFO hdrInfoIn,
810                         POVS_PACKET_HDR_INFO hdrInfoOut)
811 {
812     if ((isRecv && csumInfo.Receive.IpChecksumValueInvalid) ||
813         (!isRecv && csumInfo.Transmit.IsIPv4 &&
814         csumInfo.Transmit.IpHeaderChecksum)) {
815         PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet + hdrInfoOut->l3Offset);
816         ASSERT(hdrInfoIn->isIPv4);
817         ASSERT(ipHdr->Version == 4);
818         ipHdr->HeaderChecksum = IPChecksum((UINT8 *)ipHdr,
819             ipHdr->HeaderLength << 2,
820             (UINT16)~ipHdr->HeaderChecksum);
821         ovsUserStats.ipCsum++;
822     }
823     ASSERT(hdrInfoIn->tcpCsumNeeded == 0 && hdrInfoOut->udpCsumNeeded == 0);
824     /*
825      * calculate TCP/UDP pseudo checksum
826      */
827     if (isRecv && csumInfo.Receive.TcpChecksumValueInvalid) {
828         /*
829          * Only this case, we need to reclaculate pseudo checksum
830          * all other cases, it is assumed the pseudo checksum is
831          * filled already.
832          *
833          */
834         PTCP_HDR tcpHdr = (PTCP_HDR)(packet + hdrInfoIn->l4Offset);
835         if (hdrInfoIn->isIPv4) {
836             PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet + hdrInfoIn->l3Offset);
837             hdrInfoOut->l4PayLoad = (UINT16)(ntohs(ipHdr->TotalLength) -
838                                     (ipHdr->HeaderLength << 2));
839             tcpHdr->th_sum = IPPseudoChecksum((UINT32 *)&ipHdr->SourceAddress,
840                                          (UINT32 *)&ipHdr->DestinationAddress,
841                                          IPPROTO_TCP, hdrInfoOut->l4PayLoad);
842         } else {
843             PIPV6_HEADER ipv6Hdr = (PIPV6_HEADER)(packet + hdrInfoIn->l3Offset);
844             hdrInfoOut->l4PayLoad =
845                 (UINT16)(ntohs(ipv6Hdr->PayloadLength) +
846                 hdrInfoIn->l3Offset + sizeof(IPV6_HEADER)-
847                 hdrInfoIn->l4Offset);
848             ASSERT(hdrInfoIn->isIPv6);
849             tcpHdr->th_sum =
850                 IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->SourceAddress,
851                 (UINT32 *)&ipv6Hdr->DestinationAddress,
852                 IPPROTO_TCP, hdrInfoOut->l4PayLoad);
853         }
854         hdrInfoOut->tcpCsumNeeded = 1;
855         ovsUserStats.recalTcpCsum++;
856     } else if (!isRecv) {
857         if (csumInfo.Transmit.TcpChecksum) {
858             hdrInfoOut->tcpCsumNeeded = 1;
859         } else if (csumInfo.Transmit.UdpChecksum) {
860             hdrInfoOut->udpCsumNeeded = 1;
861         }
862         if (hdrInfoOut->tcpCsumNeeded || hdrInfoOut->udpCsumNeeded) {
863 #ifdef DBG
864             UINT16 sum, *ptr;
865             UINT8 proto =
866                 hdrInfoOut->tcpCsumNeeded ? IPPROTO_TCP : IPPROTO_UDP;
867 #endif
868             if (hdrInfoIn->isIPv4) {
869                 PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet + hdrInfoIn->l3Offset);
870                 hdrInfoOut->l4PayLoad = (UINT16)(ntohs(ipHdr->TotalLength) -
871                     (ipHdr->HeaderLength << 2));
872 #ifdef DBG
873                 sum = IPPseudoChecksum((UINT32 *)&ipHdr->SourceAddress,
874                     (UINT32 *)&ipHdr->DestinationAddress,
875                     proto, hdrInfoOut->l4PayLoad);
876 #endif
877             } else {
878                 PIPV6_HEADER ipv6Hdr = (PIPV6_HEADER)(packet +
879                     hdrInfoIn->l3Offset);
880                 hdrInfoOut->l4PayLoad =
881                     (UINT16)(ntohs(ipv6Hdr->PayloadLength) +
882                     hdrInfoIn->l3Offset + sizeof(IPV6_HEADER)-
883                     hdrInfoIn->l4Offset);
884                 ASSERT(hdrInfoIn->isIPv6);
885 #ifdef DBG
886                 sum = IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->SourceAddress,
887                     (UINT32 *)&ipv6Hdr->DestinationAddress,
888                     proto, hdrInfoOut->l4PayLoad);
889 #endif
890             }
891 #ifdef DBG
892             ptr = (UINT16 *)(packet + hdrInfoIn->l4Offset +
893                 (hdrInfoOut->tcpCsumNeeded ?
894             TCP_CSUM_OFFSET : UDP_CSUM_OFFSET));
895             ASSERT(*ptr == sum);
896 #endif
897         }
898     }
899 }
900
901 static NTSTATUS
902 OvsGetPid(POVS_VPORT_ENTRY vport, PNET_BUFFER nb, UINT32 *pid)
903 {
904     UNREFERENCED_PARAMETER(nb);
905
906     ASSERT(vport);
907
908     /* XXX select a pid from an array of pids using a flow based hash */
909     *pid = vport->upcallPid;
910     return STATUS_SUCCESS;
911 }
912
913 /*
914  *----------------------------------------------------------------------------
915  * OvsCreateQueueNlPacket --
916  *
917  *  Create a packet which will be forwarded to user space.
918  *
919  * InputParameter:
920  *   userData: when cmd is user action, this field contain
921  *      user action data.
922  *   userDataLen: as name indicated
923  *   cmd: either miss or user action
924  *   inPort: datapath port id from which the packet is received.
925  *   key: flow Key with a tunnel key if available
926  *   nbl:  the NET_BUFFER_LIST which contain the packet
927  *   nb: the packet
928  *   isRecv: This is used to decide how to interprete the csum info
929  *   hdrInfo: include hdr info initialized during flow extraction.
930  *
931  * Results:
932  *    NULL if fail to create the packet
933  *    The packet element otherwise
934  *----------------------------------------------------------------------------
935  */
936 POVS_PACKET_QUEUE_ELEM
937 OvsCreateQueueNlPacket(PVOID userData,
938                        UINT32 userDataLen,
939                        UINT32 cmd,
940                        POVS_VPORT_ENTRY vport,
941                        OvsFlowKey *key,
942                        PNET_BUFFER_LIST nbl,
943                        PNET_BUFFER nb,
944                        BOOLEAN isRecv,
945                        POVS_PACKET_HDR_INFO hdrInfo)
946 {
947 #define VLAN_TAG_SIZE 4
948     UINT32 allocLen, dataLen, extraLen;
949     POVS_PACKET_QUEUE_ELEM elem;
950     UINT8 *src, *dst;
951     NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
952     NDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo;
953     OvsIPv4TunnelKey *tunnelKey = (OvsIPv4TunnelKey *)&key->tunKey;
954     UINT32 pid;
955     UINT32 nlMsgSize;
956     NL_BUFFER nlBuf;
957     PNL_MSG_HDR nlMsg;
958
959     if (vport == NULL){
960         /* No vport is not fatal. */
961         return NULL;
962     }
963
964     OvsGetPid(vport, nb, &pid);
965
966     if (!pid) {
967         /*
968          * There is no userspace queue created yet, so there is no point for
969          * creating a new packet to be queued.
970          */
971         return NULL;
972     }
973
974     csumInfo.Value = NET_BUFFER_LIST_INFO(nbl, TcpIpChecksumNetBufferListInfo);
975
976     if (isRecv && (csumInfo.Receive.TcpChecksumFailed ||
977                   (csumInfo.Receive.UdpChecksumFailed && !hdrInfo->udpCsumZero) ||
978                   csumInfo.Receive.IpChecksumFailed)) {
979         OVS_LOG_INFO("Packet dropped due to checksum failure.");
980         ovsUserStats.dropDuetoChecksum++;
981         return NULL;
982     }
983
984     vlanInfo.Value = NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo);
985     extraLen = vlanInfo.TagHeader.VlanId ? VLAN_TAG_SIZE : 0;
986
987     dataLen = NET_BUFFER_DATA_LENGTH(nb);
988
989     if (NlAttrSize(dataLen) > MAXUINT16) {
990         return NULL;
991     }
992
993     nlMsgSize = OvsGetUpcallMsgSize(userData, userDataLen, tunnelKey,
994                                     dataLen + extraLen);
995
996     allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize;
997     elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
998                                                             OVS_USER_POOL_TAG);
999     if (elem == NULL) {
1000         ovsUserStats.dropDuetoResource++;
1001         return NULL;
1002     }
1003     elem->hdrInfo.value = hdrInfo->value;
1004     elem->upcallPid = pid;
1005     elem->packet.totalLen = nlMsgSize;
1006     /* XXX remove queueid */
1007     elem->packet.queue = 0;
1008     /* XXX  no need as the length is already in the NL attrib */
1009     elem->packet.userDataLen = userDataLen;
1010     elem->packet.inPort = vport->portNo;
1011     elem->packet.cmd = cmd;
1012     if (cmd == (UINT32)OVS_PACKET_CMD_MISS) {
1013         ovsUserStats.miss++;
1014     } else if (cmd == (UINT32)OVS_PACKET_CMD_ACTION) {
1015         ovsUserStats.action++;
1016     } else {
1017         ASSERT(FALSE);
1018         goto fail;
1019     }
1020     /* XXX Should we have both packetLen and TotalLen*/
1021     elem->packet.packetLen = dataLen + extraLen;
1022
1023     NlBufInit(&nlBuf, (PCHAR)elem->packet.data, nlMsgSize);
1024
1025     /*
1026      * Initialize the OVS header
1027      * Since we are pre allocating memory for the NL buffer
1028      * the attribute settings should not fail
1029      */
1030     if (!NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
1031                       0, pid, (UINT8)cmd, OVS_PACKET_VERSION,
1032                       gOvsSwitchContext->dpNo)) {
1033         goto fail;
1034     }
1035
1036     if (MapFlowKeyToNlKey(&nlBuf, key, OVS_PACKET_ATTR_KEY,
1037                           OVS_KEY_ATTR_TUNNEL) != STATUS_SUCCESS) {
1038         goto fail;
1039     }
1040
1041     /* XXX must send OVS_PACKET_ATTR_EGRESS_TUN_KEY if set by vswtchd */
1042     if (userData){
1043         if (!NlMsgPutTailUnspec(&nlBuf, OVS_PACKET_ATTR_USERDATA,
1044                                 userData, (UINT16)userDataLen)) {
1045             goto fail;
1046         }
1047     }
1048
1049     /*
1050      * Make space for the payload to be copied and set the attribute
1051      * XXX Uninit set initilizes the buffer with xero, we don't actually need
1052      * that the payload to be initailized
1053      */
1054     dst = (UINT8 *)NlMsgPutTailUnspecUninit(&nlBuf, OVS_PACKET_ATTR_PACKET,
1055                                             (UINT16)(dataLen + extraLen));
1056     if (!dst) {
1057         goto fail;
1058     }
1059
1060     /* Store the payload for csum calculation when packet is read */
1061     elem->packet.payload = dst;
1062     dst += extraLen;
1063
1064     src = NdisGetDataBuffer(nb, dataLen, dst, 1, 0);
1065     if (src == NULL) {
1066         ovsUserStats.dropDuetoResource++;
1067         goto fail;
1068     }    else if (src != dst) {
1069         /* Copy the data from the NDIS buffer to dst. */
1070         RtlCopyMemory(dst, src, dataLen);
1071     }
1072
1073     /* Set csum if was offloaded */
1074     OvsCompletePacketHeader(dst, isRecv, csumInfo, hdrInfo, &elem->hdrInfo);
1075
1076     /*
1077      * Finally insert VLAN tag
1078      */
1079     if (extraLen) {
1080         dst = elem->packet.payload;
1081         src = dst + extraLen;
1082         ((UINT32 *)dst)[0] = ((UINT32 *)src)[0];
1083         ((UINT32 *)dst)[1] = ((UINT32 *)src)[1];
1084         ((UINT32 *)dst)[2] = ((UINT32 *)src)[2];
1085         dst += 12;
1086         ((UINT16 *)dst)[0] = htons(0x8100);
1087         ((UINT16 *)dst)[1] = htons(vlanInfo.TagHeader.VlanId |
1088             (vlanInfo.TagHeader.UserPriority << 13));
1089         elem->hdrInfo.l3Offset += VLAN_TAG_SIZE;
1090         elem->hdrInfo.l4Offset += VLAN_TAG_SIZE;
1091         ovsUserStats.vlanInsert++;
1092     }
1093
1094     nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
1095     nlMsg->nlmsgLen = NlBufSize(&nlBuf);
1096     /* 'totalLen' should be size of valid data. */
1097     elem->packet.totalLen = nlMsg->nlmsgLen;
1098
1099     return elem;
1100 fail:
1101     OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
1102     return NULL;
1103 }
1104
1105 /*
1106  * --------------------------------------------------------------------------
1107  *  Handler for the subscription for a packet queue
1108  * --------------------------------------------------------------------------
1109  */
1110 NTSTATUS
1111 OvsSubscribePacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1112                              UINT32 *replyLen)
1113 {
1114     NDIS_STATUS status;
1115     BOOLEAN rc;
1116     UINT8 join;
1117     UINT32 pid;
1118     const NL_POLICY policy[] =  {
1119         [OVS_NL_ATTR_PACKET_PID] = {.type = NL_A_U32 },
1120         [OVS_NL_ATTR_PACKET_SUBSCRIBE] = {.type = NL_A_U8 }
1121         };
1122     PNL_ATTR attrs[ARRAY_SIZE(policy)];
1123
1124     UNREFERENCED_PARAMETER(replyLen);
1125
1126     POVS_OPEN_INSTANCE instance =
1127         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1128     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1129
1130     rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1131          NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, ARRAY_SIZE(policy),
1132                        attrs, ARRAY_SIZE(attrs));
1133     if (!rc) {
1134         status = STATUS_INVALID_PARAMETER;
1135         goto done;
1136     }
1137
1138     join = NlAttrGetU8(attrs[OVS_NL_ATTR_PACKET_SUBSCRIBE]);
1139     pid = NlAttrGetU32(attrs[OVS_NL_ATTR_PACKET_PID]);
1140
1141     /* The socket subscribed with must be the same socket we perform receive*/
1142     ASSERT(pid == instance->pid);
1143
1144     status = OvsSubscribeDpIoctl(instance, pid, join);
1145
1146     /*
1147      * XXX Need to add this instance to a global data structure
1148      * which hold all packet based instances. The data structure (hash)
1149      * should be searched through the pid field of the instance for
1150      * placing the missed packet into the correct queue
1151      */
1152 done:
1153     return status;
1154 }
1155
1156 /*
1157  * --------------------------------------------------------------------------
1158  * Handler for queueing an IRP used for missed packet notification. The IRP is
1159  * completed when a packet received and mismatched. STATUS_PENDING is returned
1160  * on success. User mode keep a pending IRP at all times.
1161  * --------------------------------------------------------------------------
1162  */
1163 NTSTATUS
1164 OvsPendPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1165                        UINT32 *replyLen)
1166 {
1167     UNREFERENCED_PARAMETER(replyLen);
1168
1169     POVS_OPEN_INSTANCE instance =
1170         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1171
1172     /*
1173      * XXX access to packet queue must be through acquiring a lock as user mode
1174      * could unsubscribe and the instnace will be freed.
1175      */
1176     return OvsWaitDpIoctl(usrParamsCtx->irp, instance->fileObject);
1177 }
1178
1179 /*
1180  * --------------------------------------------------------------------------
1181  * Handler for reading missed pacckets from the driver event queue. This
1182  * handler is executed when user modes issues a socket receive on a socket
1183  * --------------------------------------------------------------------------
1184  */
1185 NTSTATUS
1186 OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1187                        UINT32 *replyLen)
1188 {
1189 #ifdef DBG
1190     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1191 #endif
1192     POVS_OPEN_INSTANCE instance =
1193         (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1194     NTSTATUS status;
1195
1196     ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1197
1198     /* Should never read events with a dump socket */
1199     ASSERT(instance->dumpState.ovsMsg == NULL);
1200
1201     /* Must have an packet queue */
1202     ASSERT(instance->packetQueue != NULL);
1203
1204     /* Output buffer has been validated while validating read dev op. */
1205     ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1206
1207     /* Read a packet from the instance queue */
1208     status = OvsReadDpIoctl(instance->fileObject, usrParamsCtx->outputBuffer,
1209                             usrParamsCtx->outputLength, replyLen);
1210     return status;
1211 }