netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / datapath-windows / ovsext / Oid.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 #include "precomp.h"
18 #include "Switch.h"
19 #include "Vport.h"
20 #include "NetProto.h"
21 #include "User.h"
22 #include "Flow.h"
23 #include "Event.h"
24 #include "User.h"
25 #include "Oid.h"
26
27 /* Due to an imported header file */
28 #pragma warning( disable:4505 )
29
30 #ifdef OVS_DBG_MOD
31 #undef OVS_DBG_MOD
32 #endif
33 #define OVS_DBG_MOD OVS_DBG_DISPATCH
34 #include "Debug.h"
35
36 typedef struct _OVS_OID_CONTEXT {
37     NDIS_EVENT oidComplete;
38     NDIS_STATUS status;
39 } OVS_OID_CONTEXT, *POVS_OID_CONTEXT;
40
41
42 VOID
43 OvsExtOidRequestComplete(NDIS_HANDLE filterModuleContext,
44                          PNDIS_OID_REQUEST oidRequest,
45                          NDIS_STATUS status);
46 static VOID
47 OvsOidRequestCompleteMethod(POVS_SWITCH_CONTEXT switchObject,
48                             PNDIS_OID_REQUEST oidRequest,
49                             PNDIS_OID_REQUEST origOidRequest,
50                             NDIS_STATUS status);
51 static VOID
52 OvsOidRequestCompleteSetInfo(POVS_SWITCH_CONTEXT switchObject,
53                             PNDIS_OID_REQUEST oidRequest,
54                             PNDIS_OID_REQUEST origOidRequest,
55                             NDIS_STATUS status);
56 static VOID
57 OvsOidRequestCompleteQuery(POVS_SWITCH_CONTEXT switchObject,
58                            PNDIS_OID_REQUEST oidRequest,
59                            PNDIS_OID_REQUEST origOidRequest,
60                            NDIS_STATUS status);
61
62 static NDIS_STATUS
63 OvsProcessSetOidPortProp(POVS_SWITCH_CONTEXT switchObject,
64                          PNDIS_OID_REQUEST oidRequest);
65 static NDIS_STATUS
66 OvsProcessSetOidPort(POVS_SWITCH_CONTEXT switchObject,
67                      PNDIS_OID_REQUEST oidRequest);
68 static NDIS_STATUS
69 OvsProcessSetOidNic(POVS_SWITCH_CONTEXT switchObject,
70                     PNDIS_OID_REQUEST oidRequest);
71
72 __inline BOOLEAN
73 OvsCheckOidHeaderFunc(PNDIS_OBJECT_HEADER header,
74                   LONG propRev,
75                   LONG propSize)
76 {
77     return header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
78            header->Revision < propRev ||
79            header->Size < propSize;
80 }
81
82 #define OvsCheckOidHeader(_hdr, _rev) \
83         OvsCheckOidHeaderFunc(_hdr, _rev, ##NDIS_SIZEOF_##_rev)
84
85 static __inline VOID
86 OvsOidSetOrigRequest(PNDIS_OID_REQUEST clonedRequest,
87                      PNDIS_OID_REQUEST origRequest)
88 {
89     *(PVOID*)(&clonedRequest->SourceReserved[0]) = origRequest;
90 }
91
92 static __inline PNDIS_OID_REQUEST
93 OvsOidGetOrigRequest(PNDIS_OID_REQUEST clonedRequest)
94 {
95     return *((PVOID*)(&clonedRequest->SourceReserved[0]));
96 }
97
98 static __inline VOID
99 OvsOidSetContext(PNDIS_OID_REQUEST clonedRequest,
100                  POVS_OID_CONTEXT origRequest)
101 {
102     *(PVOID*)(&clonedRequest->SourceReserved[8]) = origRequest;
103 }
104
105 static __inline POVS_OID_CONTEXT
106 OvsOidGetContext(PNDIS_OID_REQUEST clonedRequest)
107 {
108     return *((PVOID*)(&clonedRequest->SourceReserved[8]));
109 }
110
111 static NDIS_STATUS
112 OvsProcessSetOidPortProp(POVS_SWITCH_CONTEXT switchObject,
113                          PNDIS_OID_REQUEST oidRequest)
114 {
115     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
116     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
117     PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS portPropParam =
118                                           setInfo->InformationBuffer;
119     BOOLEAN checkFailed = TRUE;
120
121     UNREFERENCED_PARAMETER(switchObject);
122
123     if (setInfo->Oid == OID_SWITCH_PORT_PROPERTY_DELETE) {
124         checkFailed = OvsCheckOidHeader(
125                       (PNDIS_OBJECT_HEADER)portPropParam,
126                       NDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS_REVISION_1);
127     } else {
128         /* it must be a add or update request */
129         checkFailed = OvsCheckOidHeader(
130                       (PNDIS_OBJECT_HEADER)portPropParam,
131                       NDIS_SWITCH_PORT_PROPERTY_PARAMETERS_REVISION_1);
132     }
133
134     if (checkFailed) {
135         status = NDIS_STATUS_INVALID_PARAMETER;
136         goto done;
137     }
138
139     if (portPropParam->PropertyType == NdisSwitchPortPropertyTypeVlan) {
140         status = NDIS_STATUS_NOT_SUPPORTED;
141         goto done;
142     }
143
144 done:
145     return status;
146 }
147
148 static NDIS_STATUS
149 OvsProcessSetOidPort(POVS_SWITCH_CONTEXT switchObject,
150                      PNDIS_OID_REQUEST oidRequest)
151 {
152     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
153     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
154     PNDIS_SWITCH_PORT_PARAMETERS portParam = setInfo->InformationBuffer;
155
156     if (OvsCheckOidHeader((PNDIS_OBJECT_HEADER)portParam,
157                            NDIS_SWITCH_PORT_PARAMETERS_REVISION_1)) {
158         status = NDIS_STATUS_NOT_SUPPORTED;
159         goto done;
160     }
161
162     if (portParam->IsValidationPort) {
163         /* Validation ports are used internally by the Hyper-V switch
164          * to validate and verify settings. We must skip handling them,
165          * and return STATUS_SUCCESS as the OID result
166          */
167         return NDIS_STATUS_SUCCESS;
168     }
169
170     switch(setInfo->Oid) {
171     case OID_SWITCH_PORT_CREATE:
172         status = HvCreatePort(switchObject, portParam, 0);
173         break;
174     case OID_SWITCH_PORT_UPDATED:
175         status = HvUpdatePort(switchObject, portParam);
176        break;
177     case OID_SWITCH_PORT_TEARDOWN:
178         HvTeardownPort(switchObject, portParam);
179         break;
180     case OID_SWITCH_PORT_DELETE:
181         HvDeletePort(switchObject, portParam);
182         break;
183     default:
184         break;
185     }
186
187 done:
188     return status;
189 }
190
191 static NDIS_STATUS
192 OvsProcessSetOidNic(POVS_SWITCH_CONTEXT switchObject,
193                     PNDIS_OID_REQUEST oidRequest)
194 {
195     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
196     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
197     PNDIS_SWITCH_NIC_PARAMETERS nicParam = setInfo->InformationBuffer;
198
199     if (OvsCheckOidHeader((PNDIS_OBJECT_HEADER)nicParam,
200                            NDIS_SWITCH_NIC_PARAMETERS_REVISION_1)) {
201         status = NDIS_STATUS_NOT_SUPPORTED;
202         goto done;
203     }
204
205     switch(setInfo->Oid) {
206     case OID_SWITCH_NIC_CREATE:
207         status = HvCreateNic(switchObject, nicParam);
208         break;
209     case OID_SWITCH_NIC_CONNECT:
210         HvConnectNic(switchObject, nicParam);
211         break;
212     case OID_SWITCH_NIC_UPDATED:
213         HvUpdateNic(switchObject, nicParam);
214         break;
215     case OID_SWITCH_NIC_DISCONNECT:
216         HvDisconnectNic(switchObject, nicParam);
217         break;
218     case OID_SWITCH_NIC_DELETE:
219         HvDeleteNic(switchObject, nicParam);
220         break;
221     default:
222         break;
223     }
224
225 done:
226     return status;
227
228 }
229
230 static NDIS_STATUS
231 OvsProcessSetOid(POVS_SWITCH_CONTEXT switchObject,
232                  PNDIS_OID_REQUEST oidRequest,
233                  PBOOLEAN complete)
234 {
235     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
236     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
237
238     *complete = FALSE;
239
240     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
241                   oidRequest, setInfo->Oid);
242
243     /* Verify the basic Oid paramters first */
244     if (setInfo->InformationBufferLength &&
245        (setInfo->InformationBufferLength < sizeof(NDIS_OBJECT_HEADER))) {
246         status = NDIS_STATUS_INVALID_OID;
247         OVS_LOG_INFO("Invalid input %d", setInfo->InformationBufferLength);
248         goto error;
249     }
250
251     /* Documentation does not specify what should be done
252      * if informationBuffer is not present. Although it mentions the
253      * structure type informationBUffer points to for each oid request,
254      * but it does not explicitly mention that it is a MUST.
255      * hence we are following this scenario same way as what sample code
256      * mentions. */
257     if (!(setInfo->InformationBufferLength)) {
258         /* We cannot do anything about this oid request,
259          * lets just pass it down. */
260         OVS_LOG_INFO("Buffer Length Zero");
261         goto done;
262     }
263
264     switch(setInfo->Oid) {
265     case OID_SWITCH_PORT_PROPERTY_ADD:
266     case OID_SWITCH_PORT_PROPERTY_UPDATE:
267     case OID_SWITCH_PORT_PROPERTY_DELETE:
268         status = OvsProcessSetOidPortProp(switchObject, oidRequest);
269     break;
270
271     case OID_SWITCH_PORT_CREATE:
272     case OID_SWITCH_PORT_UPDATED:
273     case OID_SWITCH_PORT_TEARDOWN:
274     case OID_SWITCH_PORT_DELETE:
275         status = OvsProcessSetOidPort(switchObject, oidRequest);
276     break;
277
278     case OID_SWITCH_NIC_CREATE:
279     case OID_SWITCH_NIC_CONNECT:
280     case OID_SWITCH_NIC_UPDATED:
281     case OID_SWITCH_NIC_DISCONNECT:
282     case OID_SWITCH_NIC_DELETE:
283         status = OvsProcessSetOidNic(switchObject, oidRequest);
284     break;
285
286     default:
287         /* Non handled OID request */
288         break;
289     }
290
291     if (status != NDIS_STATUS_SUCCESS) {
292         goto error;
293     }
294
295     goto done;
296
297 error:
298     *complete = TRUE;
299 done:
300     OVS_LOG_TRACE("Exit: status %8x.", status);
301     return status;
302 }
303
304 static NDIS_STATUS
305 OvsProcessMethodOid(POVS_SWITCH_CONTEXT switchObject,
306                     PNDIS_OID_REQUEST oidRequest,
307                     PBOOLEAN complete,
308                     PULONG bytesNeededParam)
309 {
310     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
311     struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
312     struct _SET *nicReqSetInfo = NULL;
313     PNDIS_OBJECT_HEADER header = NULL;
314     PNDIS_OID_REQUEST nicOidRequest = NULL;
315
316     UNREFERENCED_PARAMETER(switchObject);
317
318     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
319                   oidRequest, methodInfo->Oid);
320
321     *complete = FALSE;
322     *bytesNeededParam = 0;
323     header = methodInfo->InformationBuffer;
324
325     switch(methodInfo->Oid) {
326     /* We deal with only OID_SWITCH_NIC_REQUEST as of now */
327     case  OID_SWITCH_NIC_REQUEST:
328         if (OvsCheckOidHeader(header,
329             NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1)) {
330             OVS_LOG_INFO("Check Header failed");
331             status = NDIS_STATUS_NOT_SUPPORTED;
332             *complete = TRUE;
333             goto done;
334         }
335
336         nicOidRequest = (((PNDIS_SWITCH_NIC_OID_REQUEST)header)->OidRequest);
337         nicReqSetInfo = &(nicOidRequest->DATA.SET_INFORMATION);
338
339         /* Fail the SR-IOV VF case */
340         if ((nicOidRequest->RequestType == NdisRequestSetInformation) &&
341                    (nicReqSetInfo->Oid == OID_NIC_SWITCH_ALLOCATE_VF)) {
342             OVS_LOG_INFO("We do not support Oid: "
343                          "OID_NIC_SWITCH_ALLOCATE_VF");
344             status = NDIS_STATUS_FAILURE;
345             *complete = TRUE;
346         }
347         break;
348     default:
349         /* No op */
350         break;
351     }
352
353 done:
354     OVS_LOG_TRACE("Exit: status %8x.", status);
355     return status;
356 }
357
358 /*
359  * --------------------------------------------------------------------------
360  * Implements filter driver's FilterOidRequest function.
361  * --------------------------------------------------------------------------
362  */
363
364 NDIS_STATUS
365 OvsExtOidRequest(NDIS_HANDLE filterModuleContext,
366                  PNDIS_OID_REQUEST oidRequest)
367 {
368     POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext;
369     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
370     PNDIS_OID_REQUEST clonedOidRequest = NULL;
371     struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
372     BOOLEAN completeOid = FALSE;
373     ULONG bytesNeeded = 0;
374
375     OVS_LOG_TRACE("Enter: oidRequest %p, reqType: %d",
376                   oidRequest, oidRequest->RequestType);
377     status = NdisAllocateCloneOidRequest(switchObject->NdisFilterHandle,
378                                          oidRequest, OVS_MEMORY_TAG,
379                                          &clonedOidRequest);
380     if (status != NDIS_STATUS_SUCCESS) {
381         goto done;
382     }
383
384     NdisInterlockedIncrement(&(switchObject->pendingOidCount));
385
386     /* set the original oid request in cloned one. */
387     OvsOidSetOrigRequest(clonedOidRequest, oidRequest);
388     OvsOidSetContext(clonedOidRequest, NULL);
389
390     switch(clonedOidRequest->RequestType) {
391     case NdisRequestSetInformation:
392         status = OvsProcessSetOid(switchObject, clonedOidRequest,
393                                                    &completeOid);
394         break;
395     case NdisRequestMethod:
396         status = OvsProcessMethodOid(switchObject, clonedOidRequest,
397                                      &completeOid, &bytesNeeded);
398         break;
399     default:
400         /* We do not handle other request types as of now.
401          * We are just a passthrough for those. */
402         break;
403     }
404
405     if (completeOid == TRUE) {
406         /* dont leave any reference back to original request,
407          * even if we are freeing it up. */
408         OVS_LOG_INFO("Complete True oidRequest %p.", oidRequest);
409         OvsOidSetOrigRequest(clonedOidRequest, NULL);
410         NdisFreeCloneOidRequest(switchObject->NdisFilterHandle,
411                                              clonedOidRequest);
412         methodInfo->BytesNeeded = bytesNeeded;
413         NdisInterlockedDecrement(&switchObject->pendingOidCount);
414         goto done;
415     }
416
417     /* pass the request down */
418     status = NdisFOidRequest(switchObject->NdisFilterHandle, clonedOidRequest);
419     if (status != NDIS_STATUS_PENDING) {
420         OvsExtOidRequestComplete(switchObject, clonedOidRequest, status);
421         /* sample code says so */
422         status = NDIS_STATUS_PENDING;
423     }
424
425 done:
426     OVS_LOG_TRACE("Exit: status %8x.", status);
427     return status;
428 }
429
430 /*
431  * --------------------------------------------------------------------------
432  * Implements filter driver's FilterOidRequestComplete function.
433  * --------------------------------------------------------------------------
434  */
435 VOID
436 OvsExtOidRequestComplete(NDIS_HANDLE filterModuleContext,
437                          PNDIS_OID_REQUEST oidRequest,
438                          NDIS_STATUS status)
439 {
440     POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext;
441     PNDIS_OID_REQUEST origReq = OvsOidGetOrigRequest(oidRequest);
442     POVS_OID_CONTEXT oidContext = OvsOidGetContext(oidRequest);
443
444     /* Only one of the two should be set */
445     ASSERT(origReq != NULL || oidContext != NULL);
446     ASSERT(oidContext != NULL || origReq != NULL);
447
448     OVS_LOG_TRACE("Enter: oidRequest %p, reqType: %d",
449                   oidRequest, oidRequest->RequestType);
450
451     if (origReq == NULL) {
452         NdisInterlockedDecrement(&(switchObject->pendingOidCount));
453         oidContext->status = status;
454         NdisSetEvent(&oidContext->oidComplete);
455         OVS_LOG_INFO("Internally generated request");
456         goto done;
457     }
458
459     switch(oidRequest->RequestType) {
460     case NdisRequestMethod:
461         OvsOidRequestCompleteMethod(switchObject, oidRequest,
462                                     origReq, status);
463         break;
464
465     case NdisRequestSetInformation:
466         OvsOidRequestCompleteSetInfo(switchObject, oidRequest,
467                                      origReq, status);
468         break;
469
470     case NdisRequestQueryInformation:
471     case NdisRequestQueryStatistics:
472     default:
473         OvsOidRequestCompleteQuery(switchObject, oidRequest,
474                                    origReq, status);
475         break;
476     }
477
478     OvsOidSetOrigRequest(oidRequest, NULL);
479
480     NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, oidRequest);
481     NdisFOidRequestComplete(switchObject->NdisFilterHandle, origReq, status);
482     NdisInterlockedDecrement(&(switchObject->pendingOidCount));
483
484 done:
485     OVS_LOG_TRACE("Exit");
486 }
487
488 static VOID
489 OvsOidRequestCompleteMethod(POVS_SWITCH_CONTEXT switchObject,
490                             PNDIS_OID_REQUEST oidRequest,
491                             PNDIS_OID_REQUEST origOidRequest,
492                             NDIS_STATUS status)
493 {
494     UNREFERENCED_PARAMETER(status);
495     UNREFERENCED_PARAMETER(switchObject);
496
497     struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
498     struct _METHOD *origMethodInfo = &(origOidRequest->DATA.
499                                        METHOD_INFORMATION);
500
501     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
502                   oidRequest, methodInfo->Oid);
503
504     origMethodInfo->OutputBufferLength = methodInfo->OutputBufferLength;
505     origMethodInfo->BytesRead = methodInfo->BytesRead;
506     origMethodInfo->BytesNeeded = methodInfo->BytesNeeded;
507     origMethodInfo->BytesWritten = methodInfo->BytesWritten;
508
509     OVS_LOG_TRACE("Exit");
510 }
511
512 static VOID
513 OvsOidRequestCompleteSetInfo(POVS_SWITCH_CONTEXT switchObject,
514                              PNDIS_OID_REQUEST oidRequest,
515                              PNDIS_OID_REQUEST origOidRequest,
516                              NDIS_STATUS status)
517 {
518     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
519     struct _SET *origSetInfo = &(origOidRequest->DATA.SET_INFORMATION);
520     PNDIS_OBJECT_HEADER origHeader = origSetInfo->InformationBuffer;
521
522     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
523                   oidRequest, setInfo->Oid);
524
525     origSetInfo->BytesRead = setInfo->BytesRead;
526     origSetInfo->BytesNeeded = setInfo->BytesNeeded;
527
528     if (status != NDIS_STATUS_SUCCESS) {
529
530         switch(setInfo->Oid) {
531         case OID_SWITCH_PORT_CREATE:
532             HvDeletePort(switchObject,
533                          (PNDIS_SWITCH_PORT_PARAMETERS)origHeader);
534             break;
535
536         case OID_SWITCH_NIC_CREATE:
537             HvDeleteNic(switchObject,
538                         (PNDIS_SWITCH_NIC_PARAMETERS)origHeader);
539             break;
540
541         default:
542             break;
543         }
544     }
545
546     OVS_LOG_TRACE("Exit");
547 }
548
549 static VOID
550 OvsOidRequestCompleteQuery(POVS_SWITCH_CONTEXT switchObject,
551                            PNDIS_OID_REQUEST oidRequest,
552                            PNDIS_OID_REQUEST origOidRequest,
553                            NDIS_STATUS status)
554 {
555     UNREFERENCED_PARAMETER(switchObject);
556     UNREFERENCED_PARAMETER(status);
557
558     struct _QUERY *queryInfo = &((oidRequest->DATA).QUERY_INFORMATION);
559     struct _QUERY *origQueryInfo = &((origOidRequest->DATA).QUERY_INFORMATION);
560
561     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
562                   oidRequest, queryInfo->Oid);
563
564     origQueryInfo->BytesWritten = queryInfo->BytesWritten;
565     origQueryInfo->BytesNeeded = queryInfo->BytesNeeded;
566
567     OVS_LOG_TRACE("Exit");
568 }
569
570 /*
571  * --------------------------------------------------------------------------
572  * Implements filter driver's FilterCancelOidRequest function.
573  * --------------------------------------------------------------------------
574  */
575 VOID
576 OvsExtCancelOidRequest(NDIS_HANDLE filterModuleContext,
577                        PVOID requestId)
578 {
579     OVS_LOG_TRACE("Enter: requestId: %p", requestId);
580
581     UNREFERENCED_PARAMETER(filterModuleContext);
582     UNREFERENCED_PARAMETER(requestId);
583 }
584
585
586 /*
587  * --------------------------------------------------------------------------
588  * Utility function to issue the specified OID to the NDIS stack. The OID is
589  * directed towards the miniport edge of the extensible switch.
590  * An OID that gets issued may not complete immediately, and in such cases, the
591  * function waits for the OID to complete. Thus, this function must not be
592  * called at the PASSIVE_LEVEL.
593  * --------------------------------------------------------------------------
594  */
595 static NDIS_STATUS
596 OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext,
597                    NDIS_REQUEST_TYPE oidType,
598                    UINT32 oidRequestEnum,
599                    PVOID oidInputBuffer,
600                    UINT32 inputSize,
601                    PVOID oidOutputBuffer,
602                    UINT32 outputSize,
603                    UINT32 *outputSizeNeeded)
604 {
605     NDIS_STATUS status;
606     PNDIS_OID_REQUEST oidRequest;
607     POVS_OID_CONTEXT oidContext;
608     ULONG OvsExtOidRequestId =          'ISVO';
609
610     DBG_UNREFERENCED_PARAMETER(inputSize);
611     DBG_UNREFERENCED_PARAMETER(oidInputBuffer);
612
613     OVS_LOG_TRACE("Enter: switchContext: %p, oidType: %d",
614                   switchContext, oidType);
615
616     ASSERT(oidInputBuffer == NULL || inputSize != 0);
617     ASSERT(oidOutputBuffer == NULL || outputSize != 0);
618     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
619
620     oidRequest = OvsAllocateMemoryWithTag(sizeof *oidRequest,
621                                           OVS_OID_POOL_TAG);
622     if (!oidRequest) {
623         status = NDIS_STATUS_RESOURCES;
624         goto done;
625     }
626
627     oidContext = OvsAllocateMemoryWithTag(sizeof *oidContext,
628                                           OVS_OID_POOL_TAG);
629     if (!oidContext) {
630         OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG);
631         status = NDIS_STATUS_RESOURCES;
632         goto done;
633     }
634
635     RtlZeroMemory(oidRequest, sizeof *oidRequest);
636     RtlZeroMemory(oidContext, sizeof *oidContext);
637
638     oidRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
639     oidRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
640     oidRequest->Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
641
642     oidRequest->RequestType = oidType;
643     oidRequest->PortNumber = 0;
644     oidRequest->Timeout = 0;
645     oidRequest->RequestId = (PVOID)OvsExtOidRequestId;
646
647     switch(oidType) {
648     case NdisRequestQueryInformation:
649         oidRequest->DATA.QUERY_INFORMATION.Oid = oidRequestEnum;
650         oidRequest->DATA.QUERY_INFORMATION.InformationBuffer = oidOutputBuffer;
651         oidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = outputSize;
652         break;
653     default:
654         ASSERT(FALSE);
655         status = NDIS_STATUS_INVALID_PARAMETER;
656         break;
657     }
658
659     /*
660      * We make use of the SourceReserved field in the OID request to store
661      * pointers to the original OID (if any), and also context for completion
662      * (if any).
663      */
664     oidContext->status = NDIS_STATUS_SUCCESS;
665     NdisInitializeEvent(&oidContext->oidComplete);
666
667     OvsOidSetOrigRequest(oidRequest, NULL);
668     OvsOidSetContext(oidRequest, oidContext);
669
670     NdisInterlockedIncrement(&(switchContext->pendingOidCount));
671     status = NdisFOidRequest(switchContext->NdisFilterHandle, oidRequest);
672     if (status == NDIS_STATUS_PENDING) {
673         NdisWaitEvent(&oidContext->oidComplete, 0);
674     } else {
675         NdisInterlockedDecrement(&(switchContext->pendingOidCount));
676     }
677
678     if (status == NDIS_STATUS_INVALID_LENGTH ||
679         oidContext->status == NDIS_STATUS_INVALID_LENGTH) {
680         switch(oidType) {
681         case NdisRequestQueryInformation:
682             *outputSizeNeeded = oidRequest->DATA.QUERY_INFORMATION.BytesNeeded;
683         }
684     }
685
686     status = oidContext->status;
687     ASSERT(status != NDIS_STATUS_PENDING);
688
689     OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG);
690     OvsFreeMemoryWithTag(oidContext, OVS_OID_POOL_TAG);
691
692 done:
693     OVS_LOG_TRACE("Exit: status %8x.", status);
694     return status;
695 }
696
697
698 /*
699  * --------------------------------------------------------------------------
700  * Utility function to query if the extensible switch has completed activation
701  * successfully.
702  * --------------------------------------------------------------------------
703  */
704 NDIS_STATUS
705 OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext,
706                                  BOOLEAN *switchActive)
707 {
708     NDIS_STATUS status;
709     PNDIS_SWITCH_PARAMETERS switchParams;
710     UINT32 outputSizeNeeded;
711
712     OVS_LOG_TRACE("Enter: switchContext: %p, switchActive: %p",
713                   switchContext, switchActive);
714
715     switchParams = OvsAllocateMemoryWithTag(sizeof *switchParams,
716                                             OVS_OID_POOL_TAG);
717     if (!switchParams) {
718         status = NDIS_STATUS_RESOURCES;
719         goto done;
720     }
721
722     /*
723      * Even though 'switchParms' is supposed to be populated by the OID, it
724      * needs to be initialized nevertheless. Otherwise, OID returns
725      * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
726      */
727     RtlZeroMemory(switchParams, sizeof *switchParams);
728     switchParams->Header.Revision = NDIS_SWITCH_PARAMETERS_REVISION_1;
729     switchParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
730     switchParams->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1;
731
732     status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
733                                 OID_SWITCH_PARAMETERS, NULL, 0,
734                                 (PVOID)switchParams, sizeof *switchParams,
735                                 &outputSizeNeeded);
736
737     ASSERT(status != NDIS_STATUS_INVALID_LENGTH);
738     ASSERT(status != NDIS_STATUS_PENDING);
739     if (status == NDIS_STATUS_SUCCESS) {
740         ASSERT(switchParams->Header.Type == NDIS_OBJECT_TYPE_DEFAULT);
741         ASSERT(switchParams->Header.Revision == NDIS_SWITCH_PARAMETERS_REVISION_1);
742         ASSERT(switchParams->Header.Size ==
743                 NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1);
744         *switchActive = switchParams->IsActive;
745     }
746
747     OvsFreeMemoryWithTag(switchParams, OVS_OID_POOL_TAG);
748
749 done:
750     OVS_LOG_TRACE("Exit: status %8x, switchActive: %d.",
751                   status, *switchActive);
752     return status;
753 }
754
755
756 /*
757  * --------------------------------------------------------------------------
758  * Utility function to get the array of ports on the extensible switch. Upon
759  * success, the caller needs to free the returned array.
760  * --------------------------------------------------------------------------
761  */
762 NDIS_STATUS
763 OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
764                     PNDIS_SWITCH_PORT_ARRAY *portArrayOut)
765 {
766     PNDIS_SWITCH_PORT_ARRAY portArray;
767     UINT32 arraySize = sizeof *portArray;
768     NDIS_STATUS status = NDIS_STATUS_FAILURE;
769
770     OVS_LOG_TRACE("Enter: switchContext: %p, portArray: %p",
771                   switchContext, portArrayOut);
772     do {
773         UINT32 reqdArraySize;
774
775         portArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG);
776         if (!portArray) {
777             status = NDIS_STATUS_RESOURCES;
778             goto done;
779         }
780
781        /*
782         * Even though 'portArray' is supposed to be populated by the OID, it
783         * needs to be initialized nevertheless. Otherwise, OID returns
784         * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
785         */
786         RtlZeroMemory(portArray, sizeof *portArray);
787         portArray->Header.Revision = NDIS_SWITCH_PORT_ARRAY_REVISION_1;
788         portArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
789         portArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PORT_ARRAY_REVISION_1;
790
791         status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
792                                     OID_SWITCH_PORT_ARRAY, NULL, 0,
793                                     (PVOID)portArray, arraySize,
794                                     &reqdArraySize);
795         if (status == NDIS_STATUS_SUCCESS) {
796             *portArrayOut = portArray;
797             break;
798         }
799
800         OvsFreeMemoryWithTag(portArray, OVS_OID_POOL_TAG);
801         arraySize = reqdArraySize;
802         if (status != NDIS_STATUS_INVALID_LENGTH) {
803             break;
804         }
805     } while(status == NDIS_STATUS_INVALID_LENGTH);
806
807 done:
808     OVS_LOG_TRACE("Exit: status %8x.", status);
809     return status;
810 }
811
812
813 /*
814  * --------------------------------------------------------------------------
815  * Utility function to get the array of nics on the extensible switch. Upon
816  * success, the caller needs to free the returned array.
817  * --------------------------------------------------------------------------
818  */
819 NDIS_STATUS
820 OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
821                    PNDIS_SWITCH_NIC_ARRAY *nicArrayOut)
822 {
823     PNDIS_SWITCH_NIC_ARRAY nicArray;
824     UINT32 arraySize = sizeof *nicArray;
825     NDIS_STATUS status = NDIS_STATUS_FAILURE;
826
827     OVS_LOG_TRACE("Enter: switchContext: %p, nicArray: %p",
828                   switchContext, nicArrayOut);
829
830     do {
831         UINT32 reqdArraySize;
832
833         nicArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG);
834         if (!nicArray) {
835             status = NDIS_STATUS_RESOURCES;
836             goto done;
837         }
838
839        /*
840         * Even though 'nicArray' is supposed to be populated by the OID, it
841         * needs to be initialized nevertheless. Otherwise, OID returns
842         * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
843         */
844         RtlZeroMemory(nicArray, sizeof *nicArray);
845         nicArray->Header.Revision = NDIS_SWITCH_NIC_ARRAY_REVISION_1;
846         nicArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
847         nicArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_NIC_ARRAY_REVISION_1;
848
849         status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
850                                     OID_SWITCH_NIC_ARRAY, NULL, 0,
851                                     (PVOID)nicArray, arraySize,
852                                     &reqdArraySize);
853         if (status == NDIS_STATUS_SUCCESS) {
854             *nicArrayOut = nicArray;
855             break;
856         }
857
858         OvsFreeMemoryWithTag(nicArray, OVS_OID_POOL_TAG);
859         arraySize = reqdArraySize;
860         if (status != NDIS_STATUS_INVALID_LENGTH) {
861             break;
862         }
863     } while(status == NDIS_STATUS_INVALID_LENGTH);
864
865 done:
866     OVS_LOG_TRACE("Exit: status %8x.", status);
867     return status;
868 }
869
870 VOID OvsFreeSwitchPortsArray(PNDIS_SWITCH_PORT_ARRAY portsArray)
871 {
872     if (portsArray) {
873         OvsFreeMemoryWithTag(portsArray, OVS_OID_POOL_TAG);
874     }
875 }
876
877 VOID OvsFreeSwitchNicsArray(PNDIS_SWITCH_NIC_ARRAY nicsArray)
878 {
879     if (nicsArray) {
880         OvsFreeMemoryWithTag(nicsArray, OVS_OID_POOL_TAG);
881     }
882 }