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