a675347149c9301ca790f12736f2aa6a660f053d
[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     switch(setInfo->Oid) {
163     case OID_SWITCH_PORT_CREATE:
164         status = OvsCreatePort(switchObject, portParam);
165         break;
166     case OID_SWITCH_PORT_TEARDOWN:
167         OvsTeardownPort(switchObject, portParam);
168         break;
169     case OID_SWITCH_PORT_DELETE:
170         OvsDeletePort(switchObject, portParam);
171         break;
172     default:
173         break;
174     }
175
176 done:
177     return status;
178 }
179
180 static NDIS_STATUS
181 OvsProcessSetOidNic(POVS_SWITCH_CONTEXT switchObject,
182                     PNDIS_OID_REQUEST oidRequest)
183 {
184     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
185     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
186     PNDIS_SWITCH_NIC_PARAMETERS nicParam = setInfo->InformationBuffer;
187
188     if (OvsCheckOidHeader((PNDIS_OBJECT_HEADER)nicParam,
189                            NDIS_SWITCH_NIC_PARAMETERS_REVISION_1)) {
190         status = NDIS_STATUS_NOT_SUPPORTED;
191         goto done;
192     }
193
194     switch(setInfo->Oid) {
195     case OID_SWITCH_NIC_CREATE:
196         status = OvsCreateNic(switchObject, nicParam);
197         break;
198     case OID_SWITCH_NIC_CONNECT:
199         OvsConnectNic(switchObject, nicParam);
200         break;
201     case OID_SWITCH_NIC_UPDATED:
202         OvsUpdateNic(switchObject, nicParam);
203         break;
204     case OID_SWITCH_NIC_DISCONNECT:
205         OvsDisconnectNic(switchObject, nicParam);
206         break;
207     case OID_SWITCH_NIC_DELETE:
208         OvsDeleteNic(switchObject, nicParam);
209         break;
210     default:
211         break;
212     }
213
214 done:
215     return status;
216
217 }
218
219 static NDIS_STATUS
220 OvsProcessSetOid(POVS_SWITCH_CONTEXT switchObject,
221                  PNDIS_OID_REQUEST oidRequest,
222                  PBOOLEAN complete)
223 {
224     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
225     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
226
227     *complete = FALSE;
228
229     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
230                   oidRequest, setInfo->Oid);
231
232     /* Verify the basic Oid paramters first */
233     if (setInfo->InformationBufferLength &&
234        (setInfo->InformationBufferLength < sizeof(NDIS_OBJECT_HEADER))) {
235         status = NDIS_STATUS_INVALID_OID;
236         OVS_LOG_INFO("Invalid input %d", setInfo->InformationBufferLength);
237         goto error;
238     }
239
240     /* Documentation does not specify what should be done
241      * if informationBuffer is not present. Although it mentions the
242      * structure type informationBUffer points to for each oid request,
243      * but it does not explicitly mention that it is a MUST.
244      * hence we are following this scenario same way as what sample code
245      * mentions. */
246     if (!(setInfo->InformationBufferLength)) {
247         /* We cannot do anything about this oid request,
248          * lets just pass it down. */
249         OVS_LOG_INFO("Buffer Length Zero");
250         goto done;
251     }
252
253     switch(setInfo->Oid) {
254     case OID_SWITCH_PORT_PROPERTY_ADD:
255     case OID_SWITCH_PORT_PROPERTY_UPDATE:
256     case OID_SWITCH_PORT_PROPERTY_DELETE:
257         status = OvsProcessSetOidPortProp(switchObject, oidRequest);
258     break;
259
260     case OID_SWITCH_PORT_CREATE:
261     case OID_SWITCH_PORT_UPDATED:
262     case OID_SWITCH_PORT_TEARDOWN:
263     case OID_SWITCH_PORT_DELETE:
264         status = OvsProcessSetOidPort(switchObject, oidRequest);
265     break;
266
267     case OID_SWITCH_NIC_CREATE:
268     case OID_SWITCH_NIC_CONNECT:
269     case OID_SWITCH_NIC_UPDATED:
270     case OID_SWITCH_NIC_DISCONNECT:
271     case OID_SWITCH_NIC_DELETE:
272         status = OvsProcessSetOidNic(switchObject, oidRequest);
273     break;
274
275     default:
276         /* Non handled OID request */
277         break;
278     }
279
280     if (status != NDIS_STATUS_SUCCESS) {
281         goto error;
282     }
283
284     goto done;
285
286 error:
287     *complete = TRUE;
288 done:
289     OVS_LOG_TRACE("Exit: status %8x.", status);
290     return status;
291 }
292
293 static NDIS_STATUS
294 OvsProcessMethodOid(POVS_SWITCH_CONTEXT switchObject,
295                     PNDIS_OID_REQUEST oidRequest,
296                     PBOOLEAN complete,
297                     PULONG bytesNeededParam)
298 {
299     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
300     struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
301     struct _SET *nicReqSetInfo = NULL;
302     PNDIS_OBJECT_HEADER header = NULL;
303     PNDIS_OID_REQUEST nicOidRequest = NULL;
304
305     UNREFERENCED_PARAMETER(switchObject);
306
307     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
308                   oidRequest, methodInfo->Oid);
309
310     *complete = FALSE;
311     *bytesNeededParam = 0;
312     header = methodInfo->InformationBuffer;
313
314     switch(methodInfo->Oid) {
315     /* We deal with only OID_SWITCH_NIC_REQUEST as of now */
316     case  OID_SWITCH_NIC_REQUEST:
317         if (OvsCheckOidHeader(header,
318             NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1)) {
319             OVS_LOG_INFO("Check Header failed");
320             status = NDIS_STATUS_NOT_SUPPORTED;
321             *complete = TRUE;
322             goto done;
323         }
324
325         nicOidRequest = (((PNDIS_SWITCH_NIC_OID_REQUEST)header)->OidRequest);
326         nicReqSetInfo = &(nicOidRequest->DATA.SET_INFORMATION);
327
328         /* Fail the SR-IOV VF case */
329         if ((nicOidRequest->RequestType == NdisRequestSetInformation) &&
330                    (nicReqSetInfo->Oid == OID_NIC_SWITCH_ALLOCATE_VF)) {
331             OVS_LOG_INFO("We do not support Oid: "
332                          "OID_NIC_SWITCH_ALLOCATE_VF");
333             status = NDIS_STATUS_FAILURE;
334             *complete = TRUE;
335         }
336         break;
337     default:
338         /* No op */
339         break;
340     }
341
342 done:
343     OVS_LOG_TRACE("Exit: status %8x.", status);
344     return status;
345 }
346
347 /*
348  * --------------------------------------------------------------------------
349  * Implements filter driver's FilterOidRequest function.
350  * --------------------------------------------------------------------------
351  */
352
353 NDIS_STATUS
354 OvsExtOidRequest(NDIS_HANDLE filterModuleContext,
355                  PNDIS_OID_REQUEST oidRequest)
356 {
357     POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext;
358     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
359     PNDIS_OID_REQUEST clonedOidRequest = NULL;
360     struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
361     BOOLEAN completeOid = FALSE;
362     ULONG bytesNeeded = 0;
363
364     OVS_LOG_TRACE("Enter: oidRequest %p, reqType: %d",
365                   oidRequest, oidRequest->RequestType);
366     status = NdisAllocateCloneOidRequest(switchObject->NdisFilterHandle,
367                                          oidRequest, OVS_MEMORY_TAG,
368                                          &clonedOidRequest);
369     if (status != NDIS_STATUS_SUCCESS) {
370         goto done;
371     }
372
373     NdisInterlockedIncrement(&(switchObject->pendingOidCount));
374
375     /* set the original oid request in cloned one. */
376     OvsOidSetOrigRequest(clonedOidRequest, oidRequest);
377     OvsOidSetContext(clonedOidRequest, NULL);
378
379     switch(clonedOidRequest->RequestType) {
380     case NdisRequestSetInformation:
381         status = OvsProcessSetOid(switchObject, clonedOidRequest,
382                                                    &completeOid);
383         break;
384     case NdisRequestMethod:
385         status = OvsProcessMethodOid(switchObject, clonedOidRequest,
386                                      &completeOid, &bytesNeeded);
387         break;
388     default:
389         /* We do not handle other request types as of now.
390          * We are just a passthrough for those. */
391         break;
392     }
393
394     if (completeOid == TRUE) {
395         /* dont leave any reference back to original request,
396          * even if we are freeing it up. */
397         OVS_LOG_INFO("Complete True oidRequest %p.", oidRequest);
398         OvsOidSetOrigRequest(clonedOidRequest, NULL);
399         NdisFreeCloneOidRequest(switchObject->NdisFilterHandle,
400                                              clonedOidRequest);
401         methodInfo->BytesNeeded = bytesNeeded;
402         NdisInterlockedDecrement(&switchObject->pendingOidCount);
403         goto done;
404     }
405
406     /* pass the request down */
407     status = NdisFOidRequest(switchObject->NdisFilterHandle, clonedOidRequest);
408     if (status != NDIS_STATUS_PENDING) {
409         OvsExtOidRequestComplete(switchObject, clonedOidRequest, status);
410         /* sample code says so */
411         status = NDIS_STATUS_PENDING;
412     }
413
414 done:
415     OVS_LOG_TRACE("Exit: status %8x.", status);
416     return status;
417 }
418
419 /*
420  * --------------------------------------------------------------------------
421  * Implements filter driver's FilterOidRequestComplete function.
422  * --------------------------------------------------------------------------
423  */
424 VOID
425 OvsExtOidRequestComplete(NDIS_HANDLE filterModuleContext,
426                          PNDIS_OID_REQUEST oidRequest,
427                          NDIS_STATUS status)
428 {
429     POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext;
430     PNDIS_OID_REQUEST origReq = OvsOidGetOrigRequest(oidRequest);
431     POVS_OID_CONTEXT oidContext = OvsOidGetContext(oidRequest);
432
433     /* Only one of the two should be set */
434     ASSERT(origReq != NULL || oidContext != NULL);
435     ASSERT(oidContext != NULL || origReq != NULL);
436
437     OVS_LOG_TRACE("Enter: oidRequest %p, reqType: %d",
438                   oidRequest, oidRequest->RequestType);
439
440     if (origReq == NULL) {
441         NdisInterlockedDecrement(&(switchObject->pendingOidCount));
442         oidContext->status = status;
443         NdisSetEvent(&oidContext->oidComplete);
444         OVS_LOG_INFO("Internally generated request");
445         goto done;
446     }
447
448     switch(oidRequest->RequestType) {
449     case NdisRequestMethod:
450         OvsOidRequestCompleteMethod(switchObject, oidRequest,
451                                     origReq, status);
452         break;
453
454     case NdisRequestSetInformation:
455         OvsOidRequestCompleteSetInfo(switchObject, oidRequest,
456                                      origReq, status);
457         break;
458
459     case NdisRequestQueryInformation:
460     case NdisRequestQueryStatistics:
461     default:
462         OvsOidRequestCompleteQuery(switchObject, oidRequest,
463                                    origReq, status);
464         break;
465     }
466
467     OvsOidSetOrigRequest(oidRequest, NULL);
468
469     NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, oidRequest);
470     NdisFOidRequestComplete(switchObject->NdisFilterHandle, origReq, status);
471     NdisInterlockedDecrement(&(switchObject->pendingOidCount));
472
473 done:
474     OVS_LOG_TRACE("Exit");
475 }
476
477 static VOID
478 OvsOidRequestCompleteMethod(POVS_SWITCH_CONTEXT switchObject,
479                             PNDIS_OID_REQUEST oidRequest,
480                             PNDIS_OID_REQUEST origOidRequest,
481                             NDIS_STATUS status)
482 {
483     UNREFERENCED_PARAMETER(status);
484     UNREFERENCED_PARAMETER(switchObject);
485
486     struct _METHOD *methodInfo = &(oidRequest->DATA.METHOD_INFORMATION);
487     struct _METHOD *origMethodInfo = &(origOidRequest->DATA.
488                                        METHOD_INFORMATION);
489
490     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
491                   oidRequest, methodInfo->Oid);
492
493     origMethodInfo->OutputBufferLength = methodInfo->OutputBufferLength;
494     origMethodInfo->BytesRead = methodInfo->BytesRead;
495     origMethodInfo->BytesNeeded = methodInfo->BytesNeeded;
496     origMethodInfo->BytesWritten = methodInfo->BytesWritten;
497
498     OVS_LOG_TRACE("Exit");
499 }
500
501 static VOID
502 OvsOidRequestCompleteSetInfo(POVS_SWITCH_CONTEXT switchObject,
503                              PNDIS_OID_REQUEST oidRequest,
504                              PNDIS_OID_REQUEST origOidRequest,
505                              NDIS_STATUS status)
506 {
507     struct _SET *setInfo = &(oidRequest->DATA.SET_INFORMATION);
508     struct _SET *origSetInfo = &(origOidRequest->DATA.SET_INFORMATION);
509     PNDIS_OBJECT_HEADER origHeader = origSetInfo->InformationBuffer;
510
511     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
512                   oidRequest, setInfo->Oid);
513
514     origSetInfo->BytesRead = setInfo->BytesRead;
515     origSetInfo->BytesNeeded = setInfo->BytesNeeded;
516
517     if (status != NDIS_STATUS_SUCCESS) {
518
519         switch(setInfo->Oid) {
520         case OID_SWITCH_PORT_CREATE:
521             OvsDeletePort(switchObject,
522                          (PNDIS_SWITCH_PORT_PARAMETERS)origHeader);
523             break;
524
525         case OID_SWITCH_NIC_CREATE:
526             OvsDeleteNic(switchObject,
527                         (PNDIS_SWITCH_NIC_PARAMETERS)origHeader);
528             break;
529
530         default:
531             break;
532         }
533     }
534
535     OVS_LOG_TRACE("Exit");
536 }
537
538 static VOID
539 OvsOidRequestCompleteQuery(POVS_SWITCH_CONTEXT switchObject,
540                            PNDIS_OID_REQUEST oidRequest,
541                            PNDIS_OID_REQUEST origOidRequest,
542                            NDIS_STATUS status)
543 {
544     UNREFERENCED_PARAMETER(switchObject);
545     UNREFERENCED_PARAMETER(status);
546
547     struct _QUERY *queryInfo = &((oidRequest->DATA).QUERY_INFORMATION);
548     struct _QUERY *origQueryInfo = &((origOidRequest->DATA).QUERY_INFORMATION);
549
550     OVS_LOG_TRACE("Enter: oidRequest %p, Oid: %lu",
551                   oidRequest, queryInfo->Oid);
552
553     origQueryInfo->BytesWritten = queryInfo->BytesWritten;
554     origQueryInfo->BytesNeeded = queryInfo->BytesNeeded;
555
556     OVS_LOG_TRACE("Exit");
557 }
558
559 /*
560  * --------------------------------------------------------------------------
561  * Implements filter driver's FilterCancelOidRequest function.
562  * --------------------------------------------------------------------------
563  */
564 VOID
565 OvsExtCancelOidRequest(NDIS_HANDLE filterModuleContext,
566                        PVOID requestId)
567 {
568     OVS_LOG_TRACE("Enter: requestId: %p", requestId);
569
570     UNREFERENCED_PARAMETER(filterModuleContext);
571     UNREFERENCED_PARAMETER(requestId);
572 }
573
574
575 /*
576  * --------------------------------------------------------------------------
577  * Utility function to issue the specified OID to the NDIS stack. The OID is
578  * directed towards the miniport edge of the extensible switch.
579  * An OID that gets issued may not complete immediately, and in such cases, the
580  * function waits for the OID to complete. Thus, this function must not be
581  * called at the PASSIVE_LEVEL.
582  * --------------------------------------------------------------------------
583  */
584 static NDIS_STATUS
585 OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext,
586                    NDIS_REQUEST_TYPE oidType,
587                    UINT32 oidRequestEnum,
588                    PVOID oidInputBuffer,
589                    UINT32 inputSize,
590                    PVOID oidOutputBuffer,
591                    UINT32 outputSize,
592                    UINT32 *outputSizeNeeded)
593 {
594     NDIS_STATUS status;
595     PNDIS_OID_REQUEST oidRequest;
596     POVS_OID_CONTEXT oidContext;
597     ULONG OvsExtOidRequestId = 'ISVO';
598
599     DBG_UNREFERENCED_PARAMETER(inputSize);
600     DBG_UNREFERENCED_PARAMETER(oidInputBuffer);
601
602     OVS_LOG_TRACE("Enter: switchContext: %p, oidType: %d",
603                   switchContext, oidType);
604
605     ASSERT(oidInputBuffer == NULL || inputSize != 0);
606     ASSERT(oidOutputBuffer == NULL || outputSize != 0);
607     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
608
609     oidRequest = OvsAllocateMemory(sizeof *oidRequest);
610     if (!oidRequest) {
611         status = NDIS_STATUS_RESOURCES;
612         goto done;
613     }
614
615     oidContext = OvsAllocateMemory(sizeof *oidContext);
616     if (!oidContext) {
617         OvsFreeMemory(oidRequest);
618         status = NDIS_STATUS_RESOURCES;
619         goto done;
620     }
621
622     RtlZeroMemory(oidRequest, sizeof *oidRequest);
623     RtlZeroMemory(oidContext, sizeof *oidContext);
624
625     oidRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
626     oidRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
627     oidRequest->Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
628
629     oidRequest->RequestType = oidType;
630     oidRequest->PortNumber = 0;
631     oidRequest->Timeout = 0;
632     oidRequest->RequestId = (PVOID)OvsExtOidRequestId;
633
634     switch(oidType) {
635     case NdisRequestQueryInformation:
636         oidRequest->DATA.QUERY_INFORMATION.Oid = oidRequestEnum;
637         oidRequest->DATA.QUERY_INFORMATION.InformationBuffer = oidOutputBuffer;
638         oidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = outputSize;
639         break;
640     default:
641         ASSERT(FALSE);
642         status = NDIS_STATUS_INVALID_PARAMETER;
643         break;
644     }
645
646     /*
647      * We make use of the SourceReserved field in the OID request to store
648      * pointers to the original OID (if any), and also context for completion
649      * (if any).
650      */
651     oidContext->status = NDIS_STATUS_SUCCESS;
652     NdisInitializeEvent(&oidContext->oidComplete);
653
654     OvsOidSetOrigRequest(oidRequest, NULL);
655     OvsOidSetContext(oidRequest, oidContext);
656
657     NdisInterlockedIncrement(&(switchContext->pendingOidCount));
658     status = NdisFOidRequest(switchContext->NdisFilterHandle, oidRequest);
659     if (status == NDIS_STATUS_PENDING) {
660         NdisWaitEvent(&oidContext->oidComplete, 0);
661     } else {
662         NdisInterlockedDecrement(&(switchContext->pendingOidCount));
663     }
664
665     if (status == NDIS_STATUS_INVALID_LENGTH ||
666         oidContext->status == NDIS_STATUS_INVALID_LENGTH) {
667         switch(oidType) {
668         case NdisRequestQueryInformation:
669             *outputSizeNeeded = oidRequest->DATA.QUERY_INFORMATION.BytesNeeded;
670         }
671     }
672
673     status = oidContext->status;
674     ASSERT(status != NDIS_STATUS_PENDING);
675
676     OvsFreeMemory(oidRequest);
677     OvsFreeMemory(oidContext);
678
679 done:
680     OVS_LOG_TRACE("Exit: status %8x.", status);
681     return status;
682 }
683
684
685 /*
686  * --------------------------------------------------------------------------
687  * Utility function to query if the extensible switch has completed activation
688  * successfully.
689  * --------------------------------------------------------------------------
690  */
691 NDIS_STATUS
692 OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext,
693                                  BOOLEAN *switchActive)
694 {
695     NDIS_STATUS status;
696     PNDIS_SWITCH_PARAMETERS switchParams;
697     UINT32 outputSizeNeeded;
698
699     OVS_LOG_TRACE("Enter: switchContext: %p, switchActive: %p",
700                   switchContext, switchActive);
701
702     switchParams = OvsAllocateMemory(sizeof *switchParams);
703     if (!switchParams) {
704         status = NDIS_STATUS_RESOURCES;
705         goto done;
706     }
707
708     /*
709      * Even though 'switchParms' is supposed to be populated by the OID, it
710      * needs to be initialized nevertheless. Otherwise, OID returns
711      * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
712      */
713     RtlZeroMemory(switchParams, sizeof *switchParams);
714     switchParams->Header.Revision = NDIS_SWITCH_PARAMETERS_REVISION_1;
715     switchParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
716     switchParams->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1;
717
718     status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
719                                 OID_SWITCH_PARAMETERS, NULL, 0,
720                                 (PVOID)switchParams, sizeof *switchParams,
721                                 &outputSizeNeeded);
722
723     ASSERT(status != NDIS_STATUS_INVALID_LENGTH);
724     ASSERT(status != NDIS_STATUS_PENDING);
725     if (status == NDIS_STATUS_SUCCESS) {
726         ASSERT(switchParams->Header.Type == NDIS_OBJECT_TYPE_DEFAULT);
727         ASSERT(switchParams->Header.Revision == NDIS_SWITCH_PARAMETERS_REVISION_1);
728         ASSERT(switchParams->Header.Size ==
729                 NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1);
730         *switchActive = switchParams->IsActive;
731     }
732
733     OvsFreeMemory(switchParams);
734
735 done:
736     OVS_LOG_TRACE("Exit: status %8x, switchActive: %d.",
737                   status, *switchActive);
738     return status;
739 }
740
741
742 /*
743  * --------------------------------------------------------------------------
744  * Utility function to get the array of ports on the extensible switch. Upon
745  * success, the caller needs to free the returned array.
746  * --------------------------------------------------------------------------
747  */
748 NDIS_STATUS
749 OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
750                     PNDIS_SWITCH_PORT_ARRAY *portArrayOut)
751 {
752     PNDIS_SWITCH_PORT_ARRAY portArray;
753     UINT32 arraySize = sizeof *portArray;
754     NDIS_STATUS status = NDIS_STATUS_FAILURE;
755
756     OVS_LOG_TRACE("Enter: switchContext: %p, portArray: %p",
757                   switchContext, portArrayOut);
758     do {
759         UINT32 reqdArraySize;
760
761         portArray = OvsAllocateMemory(arraySize);
762         if (!portArray) {
763             status = NDIS_STATUS_RESOURCES;
764             goto done;
765         }
766
767        /*
768         * Even though 'portArray' is supposed to be populated by the OID, it
769         * needs to be initialized nevertheless. Otherwise, OID returns
770         * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
771         */
772         RtlZeroMemory(portArray, sizeof *portArray);
773         portArray->Header.Revision = NDIS_SWITCH_PORT_ARRAY_REVISION_1;
774         portArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
775         portArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PORT_ARRAY_REVISION_1;
776
777         status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
778                                     OID_SWITCH_PORT_ARRAY, NULL, 0,
779                                     (PVOID)portArray, arraySize,
780                                     &reqdArraySize);
781         if (status == NDIS_STATUS_SUCCESS) {
782             *portArrayOut = portArray;
783             break;
784         }
785
786         OvsFreeMemory(portArray);
787         arraySize = reqdArraySize;
788         if (status != NDIS_STATUS_INVALID_LENGTH) {
789             break;
790         }
791     } while(status == NDIS_STATUS_INVALID_LENGTH);
792
793 done:
794     OVS_LOG_TRACE("Exit: status %8x.", status);
795     return status;
796 }
797
798
799 /*
800  * --------------------------------------------------------------------------
801  * Utility function to get the array of nics on the extensible switch. Upon
802  * success, the caller needs to free the returned array.
803  * --------------------------------------------------------------------------
804  */
805 NDIS_STATUS
806 OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
807                    PNDIS_SWITCH_NIC_ARRAY *nicArrayOut)
808 {
809     PNDIS_SWITCH_NIC_ARRAY nicArray;
810     UINT32 arraySize = sizeof *nicArray;
811     NDIS_STATUS status = NDIS_STATUS_FAILURE;
812
813     OVS_LOG_TRACE("Enter: switchContext: %p, nicArray: %p",
814                   switchContext, nicArrayOut);
815
816     do {
817         UINT32 reqdArraySize;
818
819         nicArray = OvsAllocateMemory(arraySize);
820         if (!nicArray) {
821             status = NDIS_STATUS_RESOURCES;
822             goto done;
823         }
824
825        /*
826         * Even though 'nicArray' is supposed to be populated by the OID, it
827         * needs to be initialized nevertheless. Otherwise, OID returns
828         * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation.
829         */
830         RtlZeroMemory(nicArray, sizeof *nicArray);
831         nicArray->Header.Revision = NDIS_SWITCH_NIC_ARRAY_REVISION_1;
832         nicArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
833         nicArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_NIC_ARRAY_REVISION_1;
834
835         status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation,
836                                     OID_SWITCH_NIC_ARRAY, NULL, 0,
837                                     (PVOID)nicArray, arraySize,
838                                     &reqdArraySize);
839         if (status == NDIS_STATUS_SUCCESS) {
840             *nicArrayOut = nicArray;
841             break;
842         }
843
844         OvsFreeMemory(nicArray);
845         arraySize = reqdArraySize;
846         if (status != NDIS_STATUS_INVALID_LENGTH) {
847             break;
848         }
849     } while(status == NDIS_STATUS_INVALID_LENGTH);
850
851 done:
852     OVS_LOG_TRACE("Exit: status %8x.", status);
853     return status;
854 }