]>
Commit | Line | Data |
---|---|---|
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 | |
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 | ||
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 | ||
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: | |
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 | ||
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; | |
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 | ||
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: | |
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 | ||
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; | |
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 | |
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 | ||
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 | |
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 | ||
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 | ||
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 | ||
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 | ||
865 | done: | |
866 | OVS_LOG_TRACE("Exit: status %8x.", status); | |
867 | return status; | |
868 | } | |
5b55d0ab SV |
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 | } |