]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/Oid.c
datapath-windows: Add Geneve support
[mirror_ovs.git] / datapath-windows / ovsext / Oid.c
CommitLineData
c803536e
SS
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"
fa1324c9
SG
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"
c803536e
SS
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
fa1324c9 34#include "Debug.h"
c803536e
SS
35
36typedef struct _OVS_OID_CONTEXT {
37 NDIS_EVENT oidComplete;
38 NDIS_STATUS status;
39} OVS_OID_CONTEXT, *POVS_OID_CONTEXT;
40
41
42VOID
43OvsExtOidRequestComplete(NDIS_HANDLE filterModuleContext,
44 PNDIS_OID_REQUEST oidRequest,
45 NDIS_STATUS status);
46static VOID
47OvsOidRequestCompleteMethod(POVS_SWITCH_CONTEXT switchObject,
48 PNDIS_OID_REQUEST oidRequest,
49 PNDIS_OID_REQUEST origOidRequest,
50 NDIS_STATUS status);
51static VOID
52OvsOidRequestCompleteSetInfo(POVS_SWITCH_CONTEXT switchObject,
53 PNDIS_OID_REQUEST oidRequest,
54 PNDIS_OID_REQUEST origOidRequest,
55 NDIS_STATUS status);
56static VOID
57OvsOidRequestCompleteQuery(POVS_SWITCH_CONTEXT switchObject,
58 PNDIS_OID_REQUEST oidRequest,
59 PNDIS_OID_REQUEST origOidRequest,
60 NDIS_STATUS status);
61
62static NDIS_STATUS
63OvsProcessSetOidPortProp(POVS_SWITCH_CONTEXT switchObject,
64 PNDIS_OID_REQUEST oidRequest);
65static NDIS_STATUS
66OvsProcessSetOidPort(POVS_SWITCH_CONTEXT switchObject,
67 PNDIS_OID_REQUEST oidRequest);
68static NDIS_STATUS
69OvsProcessSetOidNic(POVS_SWITCH_CONTEXT switchObject,
70 PNDIS_OID_REQUEST oidRequest);
71
72__inline BOOLEAN
73OvsCheckOidHeaderFunc(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
85static __inline VOID
86OvsOidSetOrigRequest(PNDIS_OID_REQUEST clonedRequest,
87 PNDIS_OID_REQUEST origRequest)
88{
89 *(PVOID*)(&clonedRequest->SourceReserved[0]) = origRequest;
90}
91
92static __inline PNDIS_OID_REQUEST
93OvsOidGetOrigRequest(PNDIS_OID_REQUEST clonedRequest)
94{
95 return *((PVOID*)(&clonedRequest->SourceReserved[0]));
96}
97
98static __inline VOID
99OvsOidSetContext(PNDIS_OID_REQUEST clonedRequest,
100 POVS_OID_CONTEXT origRequest)
101{
102 *(PVOID*)(&clonedRequest->SourceReserved[8]) = origRequest;
103}
104
105static __inline POVS_OID_CONTEXT
106OvsOidGetContext(PNDIS_OID_REQUEST clonedRequest)
107{
108 return *((PVOID*)(&clonedRequest->SourceReserved[8]));
109}
110
111static NDIS_STATUS
112OvsProcessSetOidPortProp(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
144done:
145 return status;
146}
147
148static NDIS_STATUS
149OvsProcessSetOidPort(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
c99e6500
AS
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
c803536e
SS
170 switch(setInfo->Oid) {
171 case OID_SWITCH_PORT_CREATE:
958227c6 172 status = HvCreatePort(switchObject, portParam, 0);
c803536e 173 break;
b5af03d7
EE
174 case OID_SWITCH_PORT_UPDATED:
175 status = HvUpdatePort(switchObject, portParam);
176 break;
c803536e 177 case OID_SWITCH_PORT_TEARDOWN:
fa048323 178 HvTeardownPort(switchObject, portParam);
c803536e
SS
179 break;
180 case OID_SWITCH_PORT_DELETE:
fa048323 181 HvDeletePort(switchObject, portParam);
c803536e
SS
182 break;
183 default:
184 break;
185 }
186
187done:
188 return status;
189}
190
191static NDIS_STATUS
192OvsProcessSetOidNic(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:
fa048323 207 status = HvCreateNic(switchObject, nicParam);
c803536e
SS
208 break;
209 case OID_SWITCH_NIC_CONNECT:
fa048323 210 HvConnectNic(switchObject, nicParam);
c803536e
SS
211 break;
212 case OID_SWITCH_NIC_UPDATED:
fa048323 213 HvUpdateNic(switchObject, nicParam);
c803536e
SS
214 break;
215 case OID_SWITCH_NIC_DISCONNECT:
fa048323 216 HvDisconnectNic(switchObject, nicParam);
c803536e
SS
217 break;
218 case OID_SWITCH_NIC_DELETE:
fa048323 219 HvDeleteNic(switchObject, nicParam);
c803536e
SS
220 break;
221 default:
222 break;
223 }
224
225done:
226 return status;
227
228}
229
230static NDIS_STATUS
231OvsProcessSetOid(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
297error:
298 *complete = TRUE;
299done:
300 OVS_LOG_TRACE("Exit: status %8x.", status);
301 return status;
302}
303
304static NDIS_STATUS
305OvsProcessMethodOid(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
353done:
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
364NDIS_STATUS
365OvsExtOidRequest(NDIS_HANDLE filterModuleContext,
366 PNDIS_OID_REQUEST oidRequest)
367{
368 POVS_SWITCH_CONTEXT switchObject = (POVS_SWITCH_CONTEXT)filterModuleContext;
5278f698 369 NDIS_STATUS status;
c803536e
SS
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
425done:
426 OVS_LOG_TRACE("Exit: status %8x.", status);
427 return status;
428}
429
430/*
431 * --------------------------------------------------------------------------
432 * Implements filter driver's FilterOidRequestComplete function.
433 * --------------------------------------------------------------------------
434 */
435VOID
436OvsExtOidRequestComplete(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
484done:
485 OVS_LOG_TRACE("Exit");
486}
487
488static VOID
489OvsOidRequestCompleteMethod(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
512static VOID
513OvsOidRequestCompleteSetInfo(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:
fa048323 532 HvDeletePort(switchObject,
c803536e
SS
533 (PNDIS_SWITCH_PORT_PARAMETERS)origHeader);
534 break;
535
536 case OID_SWITCH_NIC_CREATE:
fa048323 537 HvDeleteNic(switchObject,
c803536e
SS
538 (PNDIS_SWITCH_NIC_PARAMETERS)origHeader);
539 break;
540
541 default:
542 break;
543 }
544 }
545
546 OVS_LOG_TRACE("Exit");
547}
548
549static VOID
550OvsOidRequestCompleteQuery(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 */
575VOID
576OvsExtCancelOidRequest(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 */
595static NDIS_STATUS
596OvsIssueOidRequest(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;
5b55d0ab 608 ULONG OvsExtOidRequestId = 'ISVO';
c803536e
SS
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
5b55d0ab
SV
620 oidRequest = OvsAllocateMemoryWithTag(sizeof *oidRequest,
621 OVS_OID_POOL_TAG);
c803536e
SS
622 if (!oidRequest) {
623 status = NDIS_STATUS_RESOURCES;
624 goto done;
625 }
626
5b55d0ab
SV
627 oidContext = OvsAllocateMemoryWithTag(sizeof *oidContext,
628 OVS_OID_POOL_TAG);
c803536e 629 if (!oidContext) {
5b55d0ab 630 OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG);
c803536e
SS
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
5b55d0ab
SV
689 OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG);
690 OvsFreeMemoryWithTag(oidContext, OVS_OID_POOL_TAG);
c803536e
SS
691
692done:
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 */
704NDIS_STATUS
705OvsQuerySwitchActivationComplete(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
5b55d0ab
SV
715 switchParams = OvsAllocateMemoryWithTag(sizeof *switchParams,
716 OVS_OID_POOL_TAG);
c803536e
SS
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
5b55d0ab 747 OvsFreeMemoryWithTag(switchParams, OVS_OID_POOL_TAG);
c803536e
SS
748
749done:
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 */
762NDIS_STATUS
763OvsGetPortsOnSwitch(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
5b55d0ab 775 portArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG);
c803536e
SS
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
5b55d0ab 800 OvsFreeMemoryWithTag(portArray, OVS_OID_POOL_TAG);
c803536e
SS
801 arraySize = reqdArraySize;
802 if (status != NDIS_STATUS_INVALID_LENGTH) {
803 break;
804 }
805 } while(status == NDIS_STATUS_INVALID_LENGTH);
806
807done:
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 */
819NDIS_STATUS
820OvsGetNicsOnSwitch(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
5b55d0ab 833 nicArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG);
c803536e
SS
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
5b55d0ab 858 OvsFreeMemoryWithTag(nicArray, OVS_OID_POOL_TAG);
c803536e
SS
859 arraySize = reqdArraySize;
860 if (status != NDIS_STATUS_INVALID_LENGTH) {
861 break;
862 }
863 } while(status == NDIS_STATUS_INVALID_LENGTH);
864
865done:
866 OVS_LOG_TRACE("Exit: status %8x.", status);
867 return status;
868}
5b55d0ab
SV
869
870VOID OvsFreeSwitchPortsArray(PNDIS_SWITCH_PORT_ARRAY portsArray)
871{
872 if (portsArray) {
873 OvsFreeMemoryWithTag(portsArray, OVS_OID_POOL_TAG);
874 }
875}
876
877VOID OvsFreeSwitchNicsArray(PNDIS_SWITCH_NIC_ARRAY nicsArray)
878{
879 if (nicsArray) {
880 OvsFreeMemoryWithTag(nicsArray, OVS_OID_POOL_TAG);
881 }
882}