]> git.proxmox.com Git - mirror_ovs.git/blob - datapath-windows/ovsext/Datapath.c
datapath-windows: Add annotations for OvsAcquireCtrlLock
[mirror_ovs.git] / datapath-windows / ovsext / Datapath.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 /*
18 * XXX: OVS_USE_NL_INTERFACE is being used to keep the legacy DPIF interface
19 * alive while we transition over to the netlink based interface.
20 * OVS_USE_NL_INTERFACE = 0 => legacy inteface to use with dpif-windows.c
21 * OVS_USE_NL_INTERFACE = 1 => netlink inteface to use with ported dpif-linux.c
22 */
23
24 #include "precomp.h"
25 #include "Switch.h"
26 #include "User.h"
27 #include "Datapath.h"
28 #include "Event.h"
29 #include "NetProto.h"
30 #include "Flow.h"
31
32 #ifdef OVS_DBG_MOD
33 #undef OVS_DBG_MOD
34 #endif
35 #define OVS_DBG_MOD OVS_DBG_DATAPATH
36 #include "Debug.h"
37
38 #define NETLINK_FAMILY_NAME_LEN 48
39
40
41 /*
42 * Netlink messages are grouped by family (aka type), and each family supports
43 * a set of commands, and can be passed both from kernel -> userspace or
44 * vice-versa. To call into the kernel, userspace uses a device operation which
45 * is outside of a netlink message.
46 *
47 * Each command results in the invocation of a handler function to implement the
48 * request functionality.
49 *
50 * Expectedly, only certain combinations of (device operation, netlink family,
51 * command) are valid.
52 *
53 * Here, we implement the basic infrastructure to perform validation on the
54 * incoming message, version checking, and also to invoke the corresponding
55 * handler to do the heavy-lifting.
56 */
57
58 /*
59 * Handler for a given netlink command. Not all the parameters are used by all
60 * the handlers.
61 */
62 typedef NTSTATUS(NetlinkCmdHandler)(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
63 UINT32 *replyLen);
64
65 typedef struct _NETLINK_CMD {
66 UINT16 cmd;
67 NetlinkCmdHandler *handler;
68 UINT32 supportedDevOp; /* Supported device operations. */
69 BOOLEAN validateDpIndex; /* Does command require a valid DP argument. */
70 } NETLINK_CMD, *PNETLINK_CMD;
71
72 /* A netlink family is a group of commands. */
73 typedef struct _NETLINK_FAMILY {
74 CHAR *name;
75 UINT16 id;
76 UINT8 version;
77 UINT8 pad1;
78 UINT16 maxAttr;
79 UINT16 pad2;
80 NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
81 UINT16 opsCount;
82 } NETLINK_FAMILY, *PNETLINK_FAMILY;
83
84 /* Handlers for the various netlink commands. */
85 static NetlinkCmdHandler OvsPendEventCmdHandler,
86 OvsSubscribeEventCmdHandler,
87 OvsReadEventCmdHandler,
88 OvsNewDpCmdHandler,
89 OvsGetDpCmdHandler,
90 OvsSetDpCmdHandler,
91 OvsSockPropCmdHandler;
92
93 NetlinkCmdHandler OvsGetNetdevCmdHandler,
94 OvsGetVportCmdHandler,
95 OvsSetVportCmdHandler,
96 OvsNewVportCmdHandler,
97 OvsDeleteVportCmdHandler,
98 OvsPendPacketCmdHandler,
99 OvsSubscribePacketCmdHandler,
100 OvsReadPacketCmdHandler,
101 OvsCtDeleteCmdHandler,
102 OvsCtDumpCmdHandler;
103
104 static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
105 UINT32 *replyLen);
106 static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
107 UINT32 *replyLen);
108 static NTSTATUS HandleDpTransactionCommon(
109 POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen);
110 static NTSTATUS OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
111 UINT32 *replyLen);
112
113 /*
114 * The various netlink families, along with the supported commands. Most of
115 * these families and commands are part of the openvswitch specification for a
116 * netlink datapath. In addition, each platform can implement a few families
117 * and commands as extensions.
118 */
119
120 /* Netlink control family: this is a Windows specific family. */
121 NETLINK_CMD nlControlFamilyCmdOps[] = {
122 { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
123 .handler = OvsPendEventCmdHandler,
124 .supportedDevOp = OVS_WRITE_DEV_OP,
125 .validateDpIndex = TRUE,
126 },
127 { .cmd = OVS_CTRL_CMD_WIN_PEND_PACKET_REQ,
128 .handler = OvsPendPacketCmdHandler,
129 .supportedDevOp = OVS_WRITE_DEV_OP,
130 .validateDpIndex = TRUE,
131 },
132 { .cmd = OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
133 .handler = OvsSubscribeEventCmdHandler,
134 .supportedDevOp = OVS_WRITE_DEV_OP,
135 .validateDpIndex = TRUE,
136 },
137 { .cmd = OVS_CTRL_CMD_PACKET_SUBSCRIBE_REQ,
138 .handler = OvsSubscribePacketCmdHandler,
139 .supportedDevOp = OVS_WRITE_DEV_OP,
140 .validateDpIndex = TRUE,
141 },
142 { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
143 .handler = OvsReadEventCmdHandler,
144 .supportedDevOp = OVS_READ_DEV_OP,
145 .validateDpIndex = FALSE,
146 },
147 { .cmd = OVS_CTRL_CMD_READ_NOTIFY,
148 .handler = OvsReadPacketCmdHandler,
149 .supportedDevOp = OVS_READ_DEV_OP,
150 .validateDpIndex = FALSE,
151 },
152 { .cmd = OVS_CTRL_CMD_SOCK_PROP,
153 .handler = OvsSockPropCmdHandler,
154 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
155 .validateDpIndex = FALSE,
156 }
157 };
158
159 NETLINK_FAMILY nlControlFamilyOps = {
160 .name = OVS_WIN_CONTROL_FAMILY,
161 .id = OVS_WIN_NL_CTRL_FAMILY_ID,
162 .version = OVS_WIN_CONTROL_VERSION,
163 .maxAttr = OVS_WIN_CONTROL_ATTR_MAX,
164 .cmds = nlControlFamilyCmdOps,
165 .opsCount = ARRAY_SIZE(nlControlFamilyCmdOps)
166 };
167
168 /* Netlink datapath family. */
169 NETLINK_CMD nlDatapathFamilyCmdOps[] = {
170 { .cmd = OVS_DP_CMD_NEW,
171 .handler = OvsNewDpCmdHandler,
172 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
173 .validateDpIndex = FALSE
174 },
175 { .cmd = OVS_DP_CMD_GET,
176 .handler = OvsGetDpCmdHandler,
177 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
178 OVS_TRANSACTION_DEV_OP,
179 .validateDpIndex = FALSE
180 },
181 { .cmd = OVS_DP_CMD_SET,
182 .handler = OvsSetDpCmdHandler,
183 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
184 OVS_TRANSACTION_DEV_OP,
185 .validateDpIndex = TRUE
186 }
187 };
188
189 NETLINK_FAMILY nlDatapathFamilyOps = {
190 .name = OVS_DATAPATH_FAMILY,
191 .id = OVS_WIN_NL_DATAPATH_FAMILY_ID,
192 .version = OVS_DATAPATH_VERSION,
193 .maxAttr = OVS_DP_ATTR_MAX,
194 .cmds = nlDatapathFamilyCmdOps,
195 .opsCount = ARRAY_SIZE(nlDatapathFamilyCmdOps)
196 };
197
198 /* Netlink packet family. */
199
200 NETLINK_CMD nlPacketFamilyCmdOps[] = {
201 { .cmd = OVS_PACKET_CMD_EXECUTE,
202 .handler = OvsNlExecuteCmdHandler,
203 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
204 .validateDpIndex = TRUE
205 }
206 };
207
208 NETLINK_FAMILY nlPacketFamilyOps = {
209 .name = OVS_PACKET_FAMILY,
210 .id = OVS_WIN_NL_PACKET_FAMILY_ID,
211 .version = OVS_PACKET_VERSION,
212 .maxAttr = OVS_PACKET_ATTR_MAX,
213 .cmds = nlPacketFamilyCmdOps,
214 .opsCount = ARRAY_SIZE(nlPacketFamilyCmdOps)
215 };
216
217 /* Netlink vport family. */
218 NETLINK_CMD nlVportFamilyCmdOps[] = {
219 { .cmd = OVS_VPORT_CMD_GET,
220 .handler = OvsGetVportCmdHandler,
221 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
222 OVS_TRANSACTION_DEV_OP,
223 .validateDpIndex = TRUE
224 },
225 { .cmd = OVS_VPORT_CMD_NEW,
226 .handler = OvsNewVportCmdHandler,
227 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
228 .validateDpIndex = TRUE
229 },
230 { .cmd = OVS_VPORT_CMD_SET,
231 .handler = OvsSetVportCmdHandler,
232 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
233 .validateDpIndex = TRUE
234 },
235 { .cmd = OVS_VPORT_CMD_DEL,
236 .handler = OvsDeleteVportCmdHandler,
237 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
238 .validateDpIndex = TRUE
239 },
240 };
241
242 NETLINK_FAMILY nlVportFamilyOps = {
243 .name = OVS_VPORT_FAMILY,
244 .id = OVS_WIN_NL_VPORT_FAMILY_ID,
245 .version = OVS_VPORT_VERSION,
246 .maxAttr = OVS_VPORT_ATTR_MAX,
247 .cmds = nlVportFamilyCmdOps,
248 .opsCount = ARRAY_SIZE(nlVportFamilyCmdOps)
249 };
250
251 /* Netlink flow family. */
252
253 NETLINK_CMD nlFlowFamilyCmdOps[] = {
254 { .cmd = OVS_FLOW_CMD_NEW,
255 .handler = OvsFlowNlCmdHandler,
256 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
257 .validateDpIndex = TRUE
258 },
259 { .cmd = OVS_FLOW_CMD_SET,
260 .handler = OvsFlowNlCmdHandler,
261 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
262 .validateDpIndex = TRUE
263 },
264 { .cmd = OVS_FLOW_CMD_DEL,
265 .handler = OvsFlowNlCmdHandler,
266 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
267 .validateDpIndex = TRUE
268 },
269 { .cmd = OVS_FLOW_CMD_GET,
270 .handler = OvsFlowNlGetCmdHandler,
271 .supportedDevOp = OVS_TRANSACTION_DEV_OP |
272 OVS_WRITE_DEV_OP | OVS_READ_DEV_OP,
273 .validateDpIndex = TRUE
274 },
275 };
276
277 NETLINK_FAMILY nlFLowFamilyOps = {
278 .name = OVS_FLOW_FAMILY,
279 .id = OVS_WIN_NL_FLOW_FAMILY_ID,
280 .version = OVS_FLOW_VERSION,
281 .maxAttr = OVS_FLOW_ATTR_MAX,
282 .cmds = nlFlowFamilyCmdOps,
283 .opsCount = ARRAY_SIZE(nlFlowFamilyCmdOps)
284 };
285
286 /* Netlink Ct family. */
287 NETLINK_CMD nlCtFamilyCmdOps[] = {
288 { .cmd = IPCTNL_MSG_CT_DELETE,
289 .handler = OvsCtDeleteCmdHandler,
290 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
291 .validateDpIndex = FALSE
292 },
293 { .cmd = IPCTNL_MSG_CT_GET,
294 .handler = OvsCtDumpCmdHandler,
295 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP,
296 .validateDpIndex = FALSE
297 }
298 };
299
300 NETLINK_FAMILY nlCtFamilyOps = {
301 .name = OVS_CT_FAMILY, /* Keep this for consistency*/
302 .id = OVS_WIN_NL_CT_FAMILY_ID, /* Keep this for consistency*/
303 .version = OVS_CT_VERSION, /* Keep this for consistency*/
304 .maxAttr = OVS_NL_CT_ATTR_MAX,
305 .cmds = nlCtFamilyCmdOps,
306 .opsCount = ARRAY_SIZE(nlCtFamilyCmdOps)
307 };
308
309 /* Netlink netdev family. */
310 NETLINK_CMD nlNetdevFamilyCmdOps[] = {
311 { .cmd = OVS_WIN_NETDEV_CMD_GET,
312 .handler = OvsGetNetdevCmdHandler,
313 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
314 .validateDpIndex = FALSE
315 },
316 };
317
318 NETLINK_FAMILY nlNetdevFamilyOps = {
319 .name = OVS_WIN_NETDEV_FAMILY,
320 .id = OVS_WIN_NL_NETDEV_FAMILY_ID,
321 .version = OVS_WIN_NETDEV_VERSION,
322 .maxAttr = OVS_WIN_NETDEV_ATTR_MAX,
323 .cmds = nlNetdevFamilyCmdOps,
324 .opsCount = ARRAY_SIZE(nlNetdevFamilyCmdOps)
325 };
326
327 static NTSTATUS MapIrpOutputBuffer(PIRP irp,
328 UINT32 bufferLength,
329 UINT32 requiredLength,
330 PVOID *buffer);
331 static NTSTATUS ValidateNetlinkCmd(UINT32 devOp,
332 POVS_OPEN_INSTANCE instance,
333 POVS_MESSAGE ovsMsg,
334 UINT32 ovsMgsLength,
335 NETLINK_FAMILY *nlFamilyOps);
336 static NTSTATUS InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
337 NETLINK_FAMILY *nlFamilyOps,
338 UINT32 *replyLen);
339
340 /* Handles to the device object for communication with userspace. */
341 NDIS_HANDLE gOvsDeviceHandle;
342 PDEVICE_OBJECT gOvsDeviceObject;
343
344 _Dispatch_type_(IRP_MJ_CREATE)
345 _Dispatch_type_(IRP_MJ_CLOSE)
346 DRIVER_DISPATCH OvsOpenCloseDevice;
347
348 _Dispatch_type_(IRP_MJ_CLEANUP)
349 DRIVER_DISPATCH OvsCleanupDevice;
350
351 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
352 DRIVER_DISPATCH OvsDeviceControl;
353
354 #ifdef ALLOC_PRAGMA
355 #pragma alloc_text(INIT, OvsCreateDeviceObject)
356 #pragma alloc_text(PAGE, OvsOpenCloseDevice)
357 #pragma alloc_text(PAGE, OvsCleanupDevice)
358 #pragma alloc_text(PAGE, OvsDeviceControl)
359 #endif // ALLOC_PRAGMA
360
361 /*
362 * We might hit this limit easily since userspace opens a netlink descriptor for
363 * each thread, and at least one descriptor per vport. Revisit this later.
364 */
365 #define OVS_MAX_OPEN_INSTANCES 512
366 #define OVS_SYSTEM_DP_NAME "ovs-system"
367
368 POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
369 UINT32 ovsNumberOfOpenInstances;
370 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
371
372 NDIS_SPIN_LOCK ovsCtrlLockObj;
373 PNDIS_SPIN_LOCK gOvsCtrlLock;
374
375 NTSTATUS
376 InitUserDumpState(POVS_OPEN_INSTANCE instance,
377 POVS_MESSAGE ovsMsg)
378 {
379 /* Clear the dumpState from a previous dump sequence. */
380 ASSERT(instance->dumpState.ovsMsg == NULL);
381 ASSERT(ovsMsg);
382
383 instance->dumpState.ovsMsg =
384 (POVS_MESSAGE)OvsAllocateMemoryWithTag(sizeof(OVS_MESSAGE),
385 OVS_DATAPATH_POOL_TAG);
386 if (instance->dumpState.ovsMsg == NULL) {
387 return STATUS_NO_MEMORY;
388 }
389 RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg,
390 sizeof *instance->dumpState.ovsMsg);
391 RtlZeroMemory(instance->dumpState.index,
392 sizeof instance->dumpState.index);
393
394 return STATUS_SUCCESS;
395 }
396
397 VOID
398 FreeUserDumpState(POVS_OPEN_INSTANCE instance)
399 {
400 if (instance->dumpState.ovsMsg != NULL) {
401 OvsFreeMemoryWithTag(instance->dumpState.ovsMsg,
402 OVS_DATAPATH_POOL_TAG);
403 RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState);
404 }
405 }
406
407 NDIS_STATUS
408 OvsInit()
409 {
410 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
411
412 gOvsCtrlLock = &ovsCtrlLockObj;
413 NdisAllocateSpinLock(gOvsCtrlLock);
414 OvsInitEventQueue();
415
416 status = OvsPerCpuDataInit();
417
418 return status;
419 }
420
421 VOID
422 OvsCleanup()
423 {
424 OvsPerCpuDataCleanup();
425 OvsCleanupEventQueue();
426 if (gOvsCtrlLock) {
427 NdisFreeSpinLock(gOvsCtrlLock);
428 gOvsCtrlLock = NULL;
429 }
430 }
431
432 _Use_decl_annotations_
433 VOID
434 OvsAcquireCtrlLock()
435 {
436 NdisAcquireSpinLock(gOvsCtrlLock);
437 }
438
439 VOID
440 OvsReleaseCtrlLock()
441 {
442 NdisReleaseSpinLock(gOvsCtrlLock);
443 }
444
445
446 /*
447 * --------------------------------------------------------------------------
448 * Creates the communication device between user and kernel, and also
449 * initializes the data associated data structures.
450 * --------------------------------------------------------------------------
451 */
452 NDIS_STATUS
453 OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
454 {
455 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
456 UNICODE_STRING deviceName;
457 UNICODE_STRING symbolicDeviceName;
458 PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
459 NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes;
460 OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle);
461
462 RtlZeroMemory(dispatchTable,
463 (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH));
464 dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice;
465 dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice;
466 dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice;
467 dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl;
468
469 NdisInitUnicodeString(&deviceName, OVS_DEVICE_NAME_NT);
470 NdisInitUnicodeString(&symbolicDeviceName, OVS_DEVICE_NAME_DOS);
471
472 RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
473
474 OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header,
475 NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
476 NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
477 sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
478
479 deviceAttributes.DeviceName = &deviceName;
480 deviceAttributes.SymbolicName = &symbolicDeviceName;
481 deviceAttributes.MajorFunctions = dispatchTable;
482 deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION);
483
484 status = NdisRegisterDeviceEx(ovsExtDriverHandle,
485 &deviceAttributes,
486 &gOvsDeviceObject,
487 &gOvsDeviceHandle);
488 if (status == NDIS_STATUS_SUCCESS) {
489 OvsRegisterSystemProvider((PVOID)gOvsDeviceObject);
490 } else {
491 OVS_LOG_ERROR("Failed to regiser pseudo device, error: 0x%08x",
492 status);
493 }
494
495 OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
496 return status;
497 }
498
499
500 VOID
501 OvsDeleteDeviceObject()
502 {
503 if (gOvsDeviceHandle) {
504 #ifdef DBG
505 POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)
506 NdisGetDeviceReservedExtension(gOvsDeviceObject);
507 if (ovsExt) {
508 ASSERT(ovsExt->numberOpenInstance == 0);
509 }
510 #endif
511
512 ASSERT(gOvsDeviceObject);
513 NdisDeregisterDeviceEx(gOvsDeviceHandle);
514 gOvsDeviceHandle = NULL;
515 gOvsDeviceObject = NULL;
516
517 OvsUnregisterSystemProvider();
518 }
519 }
520
521 POVS_OPEN_INSTANCE
522 OvsGetOpenInstance(PFILE_OBJECT fileObject,
523 UINT32 dpNo)
524 {
525 LOCK_STATE_EX lockState;
526 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
527 ASSERT(instance);
528 ASSERT(instance->fileObject == fileObject);
529 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
530
531 if (gOvsSwitchContext->dpNo != dpNo) {
532 instance = NULL;
533 }
534
535 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
536 return instance;
537 }
538
539
540 POVS_OPEN_INSTANCE
541 OvsFindOpenInstance(PFILE_OBJECT fileObject)
542 {
543 UINT32 i, j;
544 for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES &&
545 j < ovsNumberOfOpenInstances; i++) {
546 if (ovsOpenInstanceArray[i]) {
547 if (ovsOpenInstanceArray[i]->fileObject == fileObject) {
548 return ovsOpenInstanceArray[i];
549 }
550 j++;
551 }
552 }
553 return NULL;
554 }
555
556 NTSTATUS
557 OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
558 PFILE_OBJECT fileObject)
559 {
560 POVS_OPEN_INSTANCE instance =
561 (POVS_OPEN_INSTANCE)OvsAllocateMemoryWithTag(sizeof(OVS_OPEN_INSTANCE),
562 OVS_DATAPATH_POOL_TAG);
563 UINT32 i;
564
565 if (instance == NULL) {
566 return STATUS_NO_MEMORY;
567 }
568 OvsAcquireCtrlLock();
569 ASSERT(OvsFindOpenInstance(fileObject) == NULL);
570
571 if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
572 OvsReleaseCtrlLock();
573 OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
574 return STATUS_INSUFFICIENT_RESOURCES;
575 }
576 RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
577
578 for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) {
579 if (ovsOpenInstanceArray[i] == NULL) {
580 ovsOpenInstanceArray[i] = instance;
581 ovsNumberOfOpenInstances++;
582 instance->cookie = i;
583 break;
584 }
585 }
586 ASSERT(i < OVS_MAX_OPEN_INSTANCES);
587 instance->fileObject = fileObject;
588 ASSERT(fileObject->FsContext == NULL);
589 instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
590 if (instance->pid == 0) {
591 /* XXX: check for rollover. */
592 }
593 fileObject->FsContext = instance;
594 OvsReleaseCtrlLock();
595 return STATUS_SUCCESS;
596 }
597
598 static VOID
599 OvsCleanupOpenInstance(PFILE_OBJECT fileObject)
600 {
601 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
602 ASSERT(instance);
603 ASSERT(fileObject == instance->fileObject);
604 OvsCleanupEvent(instance);
605 OvsCleanupPacketQueue(instance);
606 }
607
608 VOID
609 OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
610 {
611 POVS_OPEN_INSTANCE instance;
612 ASSERT(fileObject->FsContext);
613 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
614 ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES);
615
616 OvsAcquireCtrlLock();
617 fileObject->FsContext = NULL;
618 ASSERT(ovsOpenInstanceArray[instance->cookie] == instance);
619 ovsOpenInstanceArray[instance->cookie] = NULL;
620 ovsNumberOfOpenInstances--;
621 OvsReleaseCtrlLock();
622 ASSERT(instance->eventQueue == NULL);
623 ASSERT (instance->packetQueue == NULL);
624 FreeUserDumpState(instance);
625 OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
626 }
627
628 NTSTATUS
629 OvsCompleteIrpRequest(PIRP irp,
630 ULONG_PTR infoPtr,
631 NTSTATUS status)
632 {
633 irp->IoStatus.Information = infoPtr;
634 irp->IoStatus.Status = status;
635 IoCompleteRequest(irp, IO_NO_INCREMENT);
636 return status;
637 }
638
639
640 NTSTATUS
641 OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject,
642 PIRP irp)
643 {
644 PIO_STACK_LOCATION irpSp;
645 NTSTATUS status = STATUS_SUCCESS;
646 PFILE_OBJECT fileObject;
647 POVS_DEVICE_EXTENSION ovsExt =
648 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
649
650 #pragma warning(suppress: 28118)
651 PAGED_CODE();
652 ASSERT(deviceObject == gOvsDeviceObject);
653 ASSERT(ovsExt != NULL);
654
655 irpSp = IoGetCurrentIrpStackLocation(irp);
656 fileObject = irpSp->FileObject;
657 OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u",
658 deviceObject, fileObject,
659 ovsExt->numberOpenInstance);
660
661 switch (irpSp->MajorFunction) {
662 case IRP_MJ_CREATE:
663 status = OvsAddOpenInstance(ovsExt, fileObject);
664 if (STATUS_SUCCESS == status) {
665 InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance);
666 }
667 break;
668 case IRP_MJ_CLOSE:
669 ASSERT(ovsExt->numberOpenInstance > 0);
670 OvsRemoveOpenInstance(fileObject);
671 InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance);
672 break;
673 default:
674 ASSERT(0);
675 }
676 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
677 }
678
679 _Use_decl_annotations_
680 NTSTATUS
681 OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
682 PIRP irp)
683 {
684 #pragma warning(suppress: 28118)
685 PAGED_CODE();
686 PIO_STACK_LOCATION irpSp;
687 PFILE_OBJECT fileObject;
688
689 NTSTATUS status = STATUS_SUCCESS;
690 #ifdef DBG
691 POVS_DEVICE_EXTENSION ovsExt =
692 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
693 if (ovsExt) {
694 ASSERT(ovsExt->numberOpenInstance > 0);
695 }
696 #else
697 UNREFERENCED_PARAMETER(deviceObject);
698 #endif
699 ASSERT(deviceObject == gOvsDeviceObject);
700 irpSp = IoGetCurrentIrpStackLocation(irp);
701 fileObject = irpSp->FileObject;
702
703 ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP);
704
705 OvsCleanupOpenInstance(fileObject);
706
707 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
708 }
709
710 /*
711 * --------------------------------------------------------------------------
712 * IOCTL function handler for the device.
713 * --------------------------------------------------------------------------
714 */
715 NTSTATUS
716 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
717 PIRP irp)
718 {
719 PIO_STACK_LOCATION irpSp;
720 NTSTATUS status = STATUS_SUCCESS;
721 PFILE_OBJECT fileObject;
722 PVOID inputBuffer = NULL;
723 PVOID outputBuffer = NULL;
724 UINT32 inputBufferLen, outputBufferLen;
725 UINT32 code, replyLen = 0;
726 POVS_OPEN_INSTANCE instance;
727 UINT32 devOp;
728 OVS_MESSAGE ovsMsgReadOp;
729 POVS_MESSAGE ovsMsg;
730 UINT32 ovsMsgLength = 0;
731 NETLINK_FAMILY *nlFamilyOps;
732 OVS_USER_PARAMS_CONTEXT usrParamsCtx;
733
734 #pragma warning(suppress: 28118)
735 PAGED_CODE();
736 #ifdef DBG
737 POVS_DEVICE_EXTENSION ovsExt =
738 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
739 ASSERT(deviceObject == gOvsDeviceObject);
740 ASSERT(ovsExt);
741 ASSERT(ovsExt->numberOpenInstance > 0);
742 #else
743 UNREFERENCED_PARAMETER(deviceObject);
744 #endif
745
746 irpSp = IoGetCurrentIrpStackLocation(irp);
747
748 ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
749 ASSERT(irpSp->FileObject != NULL);
750
751 fileObject = irpSp->FileObject;
752 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
753 code = irpSp->Parameters.DeviceIoControl.IoControlCode;
754 inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
755 outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
756 inputBuffer = irp->AssociatedIrp.SystemBuffer;
757
758 /* Check if the extension is enabled. */
759 if (NULL == gOvsSwitchContext) {
760 status = STATUS_NOT_FOUND;
761 goto exit;
762 }
763
764 if (!OvsAcquireSwitchContext()) {
765 status = STATUS_NOT_FOUND;
766 goto exit;
767 }
768
769 /*
770 * Validate the input/output buffer arguments depending on the type of the
771 * operation.
772 */
773 switch (code) {
774 case OVS_IOCTL_GET_PID:
775 /* Both input buffer and output buffer use the same location. */
776 outputBuffer = irp->AssociatedIrp.SystemBuffer;
777 if (outputBufferLen != 0) {
778 InitUserParamsCtx(irp, instance, 0, NULL,
779 inputBuffer, inputBufferLen,
780 outputBuffer, outputBufferLen,
781 &usrParamsCtx);
782
783 ASSERT(outputBuffer);
784 } else {
785 status = STATUS_NDIS_INVALID_LENGTH;
786 goto done;
787 }
788
789 status = OvsGetPidHandler(&usrParamsCtx, &replyLen);
790 goto done;
791
792 case OVS_IOCTL_TRANSACT:
793 /* Both input buffer and output buffer are mandatory. */
794 if (outputBufferLen != 0) {
795 ASSERT(sizeof(OVS_MESSAGE_ERROR) >= sizeof *ovsMsg);
796 status = MapIrpOutputBuffer(irp, outputBufferLen,
797 sizeof(OVS_MESSAGE_ERROR),
798 &outputBuffer);
799 if (status != STATUS_SUCCESS) {
800 goto done;
801 }
802 ASSERT(outputBuffer);
803 } else {
804 status = STATUS_NDIS_INVALID_LENGTH;
805 goto done;
806 }
807
808 if (inputBufferLen < sizeof (*ovsMsg)) {
809 status = STATUS_NDIS_INVALID_LENGTH;
810 goto done;
811 }
812
813 ovsMsg = inputBuffer;
814 ovsMsgLength = inputBufferLen;
815 devOp = OVS_TRANSACTION_DEV_OP;
816 break;
817
818 case OVS_IOCTL_READ_EVENT:
819 case OVS_IOCTL_READ_PACKET:
820 /*
821 * Output buffer is mandatory. These IOCTLs are used to read events and
822 * packets respectively. It is convenient to have separate ioctls.
823 */
824 if (outputBufferLen != 0) {
825 status = MapIrpOutputBuffer(irp, outputBufferLen,
826 sizeof(OVS_MESSAGE_ERROR),
827 &outputBuffer);
828 if (status != STATUS_SUCCESS) {
829 goto done;
830 }
831 ASSERT(outputBuffer);
832 } else {
833 status = STATUS_NDIS_INVALID_LENGTH;
834 goto done;
835 }
836 inputBuffer = NULL;
837 inputBufferLen = 0;
838
839 ovsMsg = &ovsMsgReadOp;
840 RtlZeroMemory(ovsMsg, sizeof *ovsMsg);
841 ovsMsg->nlMsg.nlmsgLen = sizeof *ovsMsg;
842 ovsMsg->nlMsg.nlmsgType = nlControlFamilyOps.id;
843 ovsMsg->nlMsg.nlmsgPid = instance->pid;
844
845 /* An "artificial" command so we can use NL family function table*/
846 ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
847 OVS_CTRL_CMD_EVENT_NOTIFY :
848 OVS_CTRL_CMD_READ_NOTIFY;
849 ovsMsg->genlMsg.version = nlControlFamilyOps.version;
850 ovsMsgLength = outputBufferLen;
851
852 devOp = OVS_READ_DEV_OP;
853 break;
854
855 case OVS_IOCTL_READ:
856 /* Output buffer is mandatory. */
857 if (outputBufferLen != 0) {
858 status = MapIrpOutputBuffer(irp, outputBufferLen,
859 sizeof(OVS_MESSAGE_ERROR),
860 &outputBuffer);
861 if (status != STATUS_SUCCESS) {
862 goto done;
863 }
864 ASSERT(outputBuffer);
865 } else {
866 status = STATUS_NDIS_INVALID_LENGTH;
867 goto done;
868 }
869
870 /*
871 * Operate in the mode that read ioctl is similar to ReadFile(). This
872 * might change as the userspace code gets implemented.
873 */
874 inputBuffer = NULL;
875 inputBufferLen = 0;
876
877 /*
878 * For implementing read (ioctl or otherwise), we need to store some
879 * state in the instance to indicate the command that started the dump
880 * operation. The state can setup 'ovsMsgReadOp' appropriately. Note
881 * that 'ovsMsgReadOp' is needed only in this function to call into the
882 * appropriate handler. The handler itself can access the state in the
883 * instance.
884 *
885 * In the absence of a dump start, return 0 bytes.
886 */
887 if (instance->dumpState.ovsMsg == NULL) {
888 replyLen = 0;
889 status = STATUS_SUCCESS;
890 goto done;
891 }
892 RtlCopyMemory(&ovsMsgReadOp, instance->dumpState.ovsMsg,
893 sizeof (ovsMsgReadOp));
894
895 /* Create an NL message for consumption. */
896 ovsMsg = &ovsMsgReadOp;
897 ovsMsgLength = sizeof (ovsMsgReadOp);
898 devOp = OVS_READ_DEV_OP;
899
900 break;
901
902 case OVS_IOCTL_WRITE:
903 /* Input buffer is mandatory. */
904 if (inputBufferLen < sizeof (*ovsMsg)) {
905 status = STATUS_NDIS_INVALID_LENGTH;
906 goto done;
907 }
908
909 ovsMsg = inputBuffer;
910 ovsMsgLength = inputBufferLen;
911 devOp = OVS_WRITE_DEV_OP;
912 break;
913
914 default:
915 status = STATUS_INVALID_DEVICE_REQUEST;
916 goto done;
917 }
918
919 ASSERT(ovsMsg);
920 switch (ovsMsg->nlMsg.nlmsgType) {
921 case NFNL_TYPE_CT_GET:
922 case NFNL_TYPE_CT_DEL:
923 nlFamilyOps = &nlCtFamilyOps;
924 break;
925 case OVS_WIN_NL_CTRL_FAMILY_ID:
926 nlFamilyOps = &nlControlFamilyOps;
927 break;
928 case OVS_WIN_NL_DATAPATH_FAMILY_ID:
929 nlFamilyOps = &nlDatapathFamilyOps;
930 break;
931 case OVS_WIN_NL_FLOW_FAMILY_ID:
932 nlFamilyOps = &nlFLowFamilyOps;
933 break;
934 case OVS_WIN_NL_PACKET_FAMILY_ID:
935 nlFamilyOps = &nlPacketFamilyOps;
936 break;
937 case OVS_WIN_NL_VPORT_FAMILY_ID:
938 nlFamilyOps = &nlVportFamilyOps;
939 break;
940 case OVS_WIN_NL_NETDEV_FAMILY_ID:
941 nlFamilyOps = &nlNetdevFamilyOps;
942 break;
943 default:
944 status = STATUS_INVALID_PARAMETER;
945 goto done;
946 }
947
948 /*
949 * For read operation, avoid duplicate validation since 'ovsMsg' is either
950 * "artificial" or was copied from a previously validated 'ovsMsg'.
951 */
952 if (devOp != OVS_READ_DEV_OP) {
953 status = ValidateNetlinkCmd(devOp, instance, ovsMsg,
954 ovsMsgLength, nlFamilyOps);
955 if (status != STATUS_SUCCESS) {
956 goto done;
957 }
958 }
959
960 InitUserParamsCtx(irp, instance, devOp, ovsMsg,
961 inputBuffer, inputBufferLen,
962 outputBuffer, outputBufferLen,
963 &usrParamsCtx);
964
965 status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
966
967 done:
968 OvsReleaseSwitchContext(gOvsSwitchContext);
969
970 exit:
971 /* Should not complete a pending IRP unless proceesing is completed. */
972 if (status == STATUS_PENDING) {
973 return status;
974 }
975 return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
976 }
977
978
979 /*
980 * --------------------------------------------------------------------------
981 * Function to validate a netlink command. Only certain combinations of
982 * (device operation, netlink family, command) are valid.
983 * --------------------------------------------------------------------------
984 */
985 static NTSTATUS
986 ValidateNetlinkCmd(UINT32 devOp,
987 POVS_OPEN_INSTANCE instance,
988 POVS_MESSAGE ovsMsg,
989 UINT32 ovsMsgLength,
990 NETLINK_FAMILY *nlFamilyOps)
991 {
992 NTSTATUS status = STATUS_INVALID_PARAMETER;
993 UINT16 i;
994
995 // We need to ensure we have enough data to process
996 if (NlMsgSize(&ovsMsg->nlMsg) > ovsMsgLength) {
997 status = STATUS_INVALID_PARAMETER;
998 goto done;
999 }
1000
1001 /*
1002 * Verify if the Netlink message is part of Netfilter Netlink
1003 * This is currently used by Conntrack
1004 */
1005 if (IS_NFNL_CMD(ovsMsg->nlMsg.nlmsgType)) {
1006
1007 /* Validate Netfilter Netlink version is 0 */
1008 if (ovsMsg->nfGenMsg.version != NFNETLINK_V0) {
1009 status = STATUS_INVALID_PARAMETER;
1010 goto done;
1011 }
1012
1013 /* Validate Netfilter Netlink Subsystem */
1014 if (NFNL_SUBSYS_ID(ovsMsg->nlMsg.nlmsgType)
1015 != NFNL_SUBSYS_CTNETLINK) {
1016 status = STATUS_INVALID_PARAMETER;
1017 goto done;
1018 }
1019
1020 /* Exit the function because there aren't any other validations */
1021 status = STATUS_SUCCESS;
1022 goto done;
1023 }
1024
1025 for (i = 0; i < nlFamilyOps->opsCount; i++) {
1026 if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
1027 /* Validate if the command is valid for the device operation. */
1028 if ((devOp & nlFamilyOps->cmds[i].supportedDevOp) == 0) {
1029 status = STATUS_INVALID_PARAMETER;
1030 goto done;
1031 }
1032
1033 /* Validate the version. */
1034 if (nlFamilyOps->version > ovsMsg->genlMsg.version) {
1035 status = STATUS_INVALID_PARAMETER;
1036 goto done;
1037 }
1038
1039 /* Validate the DP for commands that require a DP. */
1040 if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
1041 if (ovsMsg->ovsHdr.dp_ifindex !=
1042 (INT)gOvsSwitchContext->dpNo) {
1043 status = STATUS_INVALID_PARAMETER;
1044 goto done;
1045 }
1046 }
1047
1048 /* Validate the PID. */
1049 if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
1050 status = STATUS_INVALID_PARAMETER;
1051 goto done;
1052 }
1053
1054 status = STATUS_SUCCESS;
1055 break;
1056 }
1057 }
1058
1059 // validate all NlAttrs
1060 if (!NlValidateAllAttrs(&ovsMsg->nlMsg, sizeof(*ovsMsg),
1061 NlMsgAttrsLen((PNL_MSG_HDR)ovsMsg),
1062 NULL, 0)) {
1063 status = STATUS_INVALID_PARAMETER;
1064 goto done;
1065 }
1066
1067 done:
1068 return status;
1069 }
1070
1071 /*
1072 * --------------------------------------------------------------------------
1073 * Function to invoke the netlink command handler. The function also stores
1074 * the return value of the handler function to construct a 'NL_ERROR' message,
1075 * and in turn returns success to the caller.
1076 * --------------------------------------------------------------------------
1077 */
1078 static NTSTATUS
1079 InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1080 NETLINK_FAMILY *nlFamilyOps,
1081 UINT32 *replyLen)
1082 {
1083 NTSTATUS status = STATUS_INVALID_PARAMETER;
1084 UINT16 i;
1085 UINT8 cmd;
1086
1087 if (IS_NFNL_CMD(usrParamsCtx->ovsMsg->nlMsg.nlmsgType)) {
1088 /* If nlMsg is of type Netfilter-Netlink parse the Cmd accordingly */
1089 cmd = NFNL_MSG_TYPE(usrParamsCtx->ovsMsg->nlMsg.nlmsgType);
1090 } else {
1091 cmd = usrParamsCtx->ovsMsg->genlMsg.cmd;
1092 }
1093
1094 for (i = 0; i < nlFamilyOps->opsCount; i++) {
1095 if (nlFamilyOps->cmds[i].cmd == cmd) {
1096 NetlinkCmdHandler *handler = nlFamilyOps->cmds[i].handler;
1097 ASSERT(handler);
1098 if (handler) {
1099 status = handler(usrParamsCtx, replyLen);
1100 }
1101 break;
1102 }
1103 }
1104
1105 /*
1106 * Netlink socket semantics dictate that the return value of the netlink
1107 * function should be an error ONLY under fatal conditions. If the message
1108 * made it all the way to the handler function, it is not a fatal condition.
1109 * Absorb the error returned by the handler function into a 'struct
1110 * NL_ERROR' and populate the 'output buffer' to return to userspace.
1111 *
1112 * This behavior is obviously applicable only to netlink commands that
1113 * specify an 'output buffer'. For other commands, we return the error as
1114 * is.
1115 *
1116 * 'STATUS_PENDING' is a special return value and userspace is equipped to
1117 * handle it.
1118 */
1119 if (status != STATUS_SUCCESS && status != STATUS_PENDING) {
1120 if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP && *replyLen == 0) {
1121 NL_ERROR nlError = NlMapStatusToNlErr(status);
1122 OVS_MESSAGE msgInTmp = { 0 };
1123 POVS_MESSAGE msgIn = NULL;
1124 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1125 usrParamsCtx->outputBuffer;
1126
1127 if (!IS_NFNL_CMD(usrParamsCtx->ovsMsg->nlMsg.nlmsgType) &&
1128 (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_CTRL_CMD_EVENT_NOTIFY ||
1129 usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_CTRL_CMD_READ_NOTIFY)) {
1130 /* There's no input buffer associated with such requests. */
1131 NL_BUFFER nlBuffer;
1132 msgIn = &msgInTmp;
1133 NlBufInit(&nlBuffer, (PCHAR)msgIn, sizeof *msgIn);
1134 NlFillNlHdr(&nlBuffer, nlFamilyOps->id, 0, 0,
1135 usrParamsCtx->ovsInstance->pid);
1136 } else {
1137 msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1138 }
1139
1140 ASSERT(msgIn);
1141 ASSERT(msgError);
1142 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
1143 ASSERT(*replyLen != 0);
1144 }
1145
1146 if (*replyLen != 0) {
1147 status = STATUS_SUCCESS;
1148 }
1149 }
1150
1151 #ifdef DBG
1152 if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP) {
1153 ASSERT(status == STATUS_PENDING || *replyLen != 0 || status == STATUS_SUCCESS);
1154 }
1155 #endif
1156
1157 return status;
1158 }
1159
1160 /*
1161 * --------------------------------------------------------------------------
1162 * Handler for 'OVS_IOCTL_GET_PID'.
1163 *
1164 * Each handle on the device is assigned a unique PID when the handle is
1165 * created. This function passes the PID to userspace using METHOD_BUFFERED
1166 * method.
1167 * --------------------------------------------------------------------------
1168 */
1169 static NTSTATUS
1170 OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1171 UINT32 *replyLen)
1172 {
1173 NTSTATUS status = STATUS_SUCCESS;
1174 PUINT32 msgOut = (PUINT32)usrParamsCtx->outputBuffer;
1175
1176 if (usrParamsCtx->outputLength >= sizeof *msgOut) {
1177 POVS_OPEN_INSTANCE instance =
1178 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1179
1180 RtlZeroMemory(msgOut, sizeof *msgOut);
1181 RtlCopyMemory(msgOut, &instance->pid, sizeof(*msgOut));
1182 *replyLen = sizeof *msgOut;
1183 } else {
1184 *replyLen = sizeof *msgOut;
1185 status = STATUS_NDIS_INVALID_LENGTH;
1186 }
1187
1188 return status;
1189 }
1190
1191 /*
1192 * --------------------------------------------------------------------------
1193 * Utility function to fill up information about the datapath in a reply to
1194 * userspace.
1195 * --------------------------------------------------------------------------
1196 */
1197 static NTSTATUS
1198 OvsDpFillInfo(POVS_SWITCH_CONTEXT ovsSwitchContext,
1199 POVS_MESSAGE msgIn,
1200 PNL_BUFFER nlBuf)
1201 {
1202 BOOLEAN writeOk;
1203 OVS_MESSAGE msgOutTmp;
1204 OVS_DATAPATH *datapath = &ovsSwitchContext->datapath;
1205 PNL_MSG_HDR nlMsg;
1206
1207 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && NlBufRemLen(nlBuf) >= sizeof *msgIn);
1208
1209 msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_DATAPATH_FAMILY_ID;
1210 msgOutTmp.nlMsg.nlmsgFlags = 0; /* XXX: ? */
1211 msgOutTmp.nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
1212 msgOutTmp.nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
1213
1214 msgOutTmp.genlMsg.cmd = OVS_DP_CMD_GET;
1215 msgOutTmp.genlMsg.version = nlDatapathFamilyOps.version;
1216 msgOutTmp.genlMsg.reserved = 0;
1217
1218 msgOutTmp.ovsHdr.dp_ifindex = ovsSwitchContext->dpNo;
1219
1220 writeOk = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1221 if (writeOk) {
1222 writeOk = NlMsgPutTailString(nlBuf, OVS_DP_ATTR_NAME,
1223 OVS_SYSTEM_DP_NAME);
1224 }
1225 if (writeOk) {
1226 OVS_DP_STATS dpStats;
1227
1228 dpStats.n_hit = datapath->hits;
1229 dpStats.n_missed = datapath->misses;
1230 dpStats.n_lost = datapath->lost;
1231 dpStats.n_flows = datapath->nFlows;
1232 writeOk = NlMsgPutTailUnspec(nlBuf, OVS_DP_ATTR_STATS,
1233 (PCHAR)&dpStats, sizeof dpStats);
1234 }
1235 nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1236 nlMsg->nlmsgLen = NlBufSize(nlBuf);
1237
1238 return writeOk ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE;
1239 }
1240
1241 /*
1242 * --------------------------------------------------------------------------
1243 * Handler for queueing an IRP used for event notification. The IRP is
1244 * completed when a port state changes. STATUS_PENDING is returned on
1245 * success. User mode keep a pending IRP at all times.
1246 * --------------------------------------------------------------------------
1247 */
1248 static NTSTATUS
1249 OvsPendEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1250 UINT32 *replyLen)
1251 {
1252 NDIS_STATUS status;
1253
1254 UNREFERENCED_PARAMETER(replyLen);
1255
1256 POVS_OPEN_INSTANCE instance =
1257 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1258 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1259 OVS_EVENT_POLL poll;
1260
1261 poll.dpNo = msgIn->ovsHdr.dp_ifindex;
1262 status = OvsWaitEventIoctl(usrParamsCtx->irp, instance->fileObject,
1263 &poll, sizeof poll);
1264 return status;
1265 }
1266
1267 /*
1268 * --------------------------------------------------------------------------
1269 * Handler for the subscription for the event queue
1270 * --------------------------------------------------------------------------
1271 */
1272 static NTSTATUS
1273 OvsSubscribeEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1274 UINT32 *replyLen)
1275 {
1276 NDIS_STATUS status;
1277 OVS_EVENT_SUBSCRIBE request;
1278 BOOLEAN rc;
1279 UINT8 join;
1280 UINT32 mcastGrp;
1281 PNL_ATTR attrs[2];
1282 const NL_POLICY policy[] = {
1283 [OVS_NL_ATTR_MCAST_GRP] = {.type = NL_A_U32 },
1284 [OVS_NL_ATTR_MCAST_JOIN] = {.type = NL_A_U8 },
1285 };
1286
1287 UNREFERENCED_PARAMETER(replyLen);
1288
1289 POVS_OPEN_INSTANCE instance =
1290 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1291 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1292
1293 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1294 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, ARRAY_SIZE(policy),
1295 attrs, ARRAY_SIZE(attrs));
1296 if (!rc) {
1297 status = STATUS_INVALID_PARAMETER;
1298 goto done;
1299 }
1300
1301 mcastGrp = NlAttrGetU32(attrs[OVS_NL_ATTR_MCAST_GRP]);
1302 join = NlAttrGetU8(attrs[OVS_NL_ATTR_MCAST_JOIN]);
1303 request.dpNo = msgIn->ovsHdr.dp_ifindex;
1304 request.subscribe = join;
1305 request.mcastGrp = mcastGrp;
1306 request.protocol = instance->protocol;
1307 request.mask = 0;
1308
1309 /* We currently support Vport and CT related events */
1310 if (instance->protocol == NETLINK_GENERIC) {
1311 request.mask = OVS_EVENT_MASK_ALL;
1312 } else if (instance->protocol == NETLINK_NETFILTER) {
1313 if (mcastGrp == NFNLGRP_CONNTRACK_NEW) {
1314 request.mask = OVS_EVENT_CT_NEW;
1315 }
1316 if (mcastGrp == NFNLGRP_CONNTRACK_DESTROY) {
1317 request.mask = OVS_EVENT_CT_DELETE;
1318 }
1319 if (mcastGrp == NFNLGRP_CONNTRACK_UPDATE) {
1320 request.mask = OVS_EVENT_CT_UPDATE;
1321 }
1322 }
1323
1324 status = OvsSubscribeEventIoctl(instance->fileObject, &request,
1325 sizeof request);
1326 done:
1327 return status;
1328 }
1329
1330 /*
1331 * --------------------------------------------------------------------------
1332 * Command Handler for 'OVS_DP_CMD_NEW'.
1333 * --------------------------------------------------------------------------
1334 */
1335 static NTSTATUS
1336 OvsNewDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1337 UINT32 *replyLen)
1338 {
1339 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1340 }
1341
1342 /*
1343 * --------------------------------------------------------------------------
1344 * Command Handler for 'OVS_DP_CMD_GET'.
1345 *
1346 * The function handles both the dump based as well as the transaction based
1347 * 'OVS_DP_CMD_GET' command. In the dump command, it handles the initial
1348 * call to setup dump state, as well as subsequent calls to continue dumping
1349 * data.
1350 * --------------------------------------------------------------------------
1351 */
1352 static NTSTATUS
1353 OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1354 UINT32 *replyLen)
1355 {
1356 if (usrParamsCtx->devOp == OVS_TRANSACTION_DEV_OP) {
1357 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1358 } else {
1359 return HandleGetDpDump(usrParamsCtx, replyLen);
1360 }
1361 }
1362
1363 /*
1364 * --------------------------------------------------------------------------
1365 * Function for handling the transaction based 'OVS_DP_CMD_GET' command.
1366 * --------------------------------------------------------------------------
1367 */
1368 static NTSTATUS
1369 HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1370 UINT32 *replyLen)
1371 {
1372 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1373 }
1374
1375
1376 /*
1377 * --------------------------------------------------------------------------
1378 * Function for handling the dump-based 'OVS_DP_CMD_GET' command.
1379 * --------------------------------------------------------------------------
1380 */
1381 static NTSTATUS
1382 HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1383 UINT32 *replyLen)
1384 {
1385 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1386 POVS_OPEN_INSTANCE instance =
1387 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1388
1389 if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
1390 *replyLen = 0;
1391 OvsSetupDumpStart(usrParamsCtx);
1392 } else {
1393 NL_BUFFER nlBuf;
1394 NTSTATUS status;
1395 POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
1396
1397 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1398
1399 if (instance->dumpState.ovsMsg == NULL) {
1400 ASSERT(FALSE);
1401 return STATUS_INVALID_DEVICE_STATE;
1402 }
1403
1404 /* Dump state must have been deleted after previous dump operation. */
1405 ASSERT(instance->dumpState.index[0] == 0);
1406
1407 /* Output buffer has been validated while validating read dev op. */
1408 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1409
1410 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
1411 usrParamsCtx->outputLength);
1412
1413 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1414
1415 if (status != STATUS_SUCCESS) {
1416 *replyLen = 0;
1417 FreeUserDumpState(instance);
1418 return status;
1419 }
1420
1421 /* Increment the dump index. */
1422 instance->dumpState.index[0] = 1;
1423 *replyLen = msgOut->nlMsg.nlmsgLen;
1424
1425 /* Free up the dump state, since there's no more data to continue. */
1426 FreeUserDumpState(instance);
1427 }
1428
1429 return STATUS_SUCCESS;
1430 }
1431
1432
1433 /*
1434 * --------------------------------------------------------------------------
1435 * Command Handler for 'OVS_DP_CMD_SET'.
1436 * --------------------------------------------------------------------------
1437 */
1438 static NTSTATUS
1439 OvsSetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1440 UINT32 *replyLen)
1441 {
1442 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1443 }
1444
1445 /*
1446 * --------------------------------------------------------------------------
1447 * Function for handling transaction based 'OVS_DP_CMD_NEW', 'OVS_DP_CMD_GET'
1448 * and 'OVS_DP_CMD_SET' commands.
1449 *
1450 * 'OVS_DP_CMD_NEW' is implemented to keep userspace code happy. Creation of a
1451 * new datapath is not supported currently.
1452 * --------------------------------------------------------------------------
1453 */
1454 static NTSTATUS
1455 HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1456 UINT32 *replyLen)
1457 {
1458 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1459 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1460 NTSTATUS status = STATUS_SUCCESS;
1461 NL_BUFFER nlBuf;
1462 NL_ERROR nlError = NL_ERROR_SUCCESS;
1463 static const NL_POLICY ovsDatapathSetPolicy[] = {
1464 [OVS_DP_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ },
1465 [OVS_DP_ATTR_UPCALL_PID] = { .type = NL_A_U32, .optional = TRUE },
1466 [OVS_DP_ATTR_USER_FEATURES] = { .type = NL_A_U32, .optional = TRUE },
1467 };
1468 PNL_ATTR dpAttrs[ARRAY_SIZE(ovsDatapathSetPolicy)];
1469
1470 UNREFERENCED_PARAMETER(msgOut);
1471
1472 /* input buffer has been validated while validating write dev op. */
1473 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1474
1475 /* Parse any attributes in the request. */
1476 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET ||
1477 usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1478 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1479 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1480 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1481 ovsDatapathSetPolicy,
1482 ARRAY_SIZE(ovsDatapathSetPolicy),
1483 dpAttrs, ARRAY_SIZE(dpAttrs))) {
1484 return STATUS_INVALID_PARAMETER;
1485 }
1486
1487 /*
1488 * XXX: Not clear at this stage if there's any role for the
1489 * OVS_DP_ATTR_UPCALL_PID and OVS_DP_ATTR_USER_FEATURES attributes passed
1490 * from userspace.
1491 */
1492
1493 } else {
1494 RtlZeroMemory(dpAttrs, sizeof dpAttrs);
1495 }
1496
1497 /* Output buffer has been validated while validating transact dev op. */
1498 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1499
1500 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1501
1502 if (dpAttrs[OVS_DP_ATTR_NAME] != NULL) {
1503 if (!OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
1504 OVS_SYSTEM_DP_NAME)) {
1505
1506 /* Creation of new datapaths is not supported. */
1507 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET) {
1508 nlError = NL_ERROR_NOTSUPP;
1509 goto cleanup;
1510 }
1511
1512 nlError = NL_ERROR_NODEV;
1513 goto cleanup;
1514 }
1515 } else if ((UINT32)msgIn->ovsHdr.dp_ifindex != gOvsSwitchContext->dpNo) {
1516 nlError = NL_ERROR_NODEV;
1517 goto cleanup;
1518 }
1519
1520 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1521 nlError = NL_ERROR_EXIST;
1522 goto cleanup;
1523 }
1524
1525 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1526
1527 *replyLen = NlBufSize(&nlBuf);
1528
1529 cleanup:
1530 if (nlError != NL_ERROR_SUCCESS) {
1531 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1532 usrParamsCtx->outputBuffer;
1533
1534 ASSERT(msgError);
1535 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
1536 ASSERT(*replyLen != 0);
1537 }
1538
1539 return STATUS_SUCCESS;
1540 }
1541
1542
1543 NTSTATUS
1544 OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
1545 {
1546 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1547 POVS_OPEN_INSTANCE instance =
1548 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1549
1550 /* input buffer has been validated while validating write dev op. */
1551 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1552
1553 /* A write operation that does not indicate dump start is invalid. */
1554 if ((msgIn->nlMsg.nlmsgFlags & NLM_F_DUMP) != NLM_F_DUMP) {
1555 return STATUS_INVALID_PARAMETER;
1556 }
1557 /* XXX: Handle other NLM_F_* flags in the future. */
1558
1559 /*
1560 * This operation should be setting up the dump state. If there's any
1561 * previous state, clear it up so as to set it up afresh.
1562 */
1563 FreeUserDumpState(instance);
1564
1565 return InitUserDumpState(instance, msgIn);
1566 }
1567
1568
1569 /*
1570 * --------------------------------------------------------------------------
1571 * Utility function to map the output buffer in an IRP. The buffer is assumed
1572 * to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
1573 * --------------------------------------------------------------------------
1574 */
1575 static NTSTATUS
1576 MapIrpOutputBuffer(PIRP irp,
1577 UINT32 bufferLength,
1578 UINT32 requiredLength,
1579 PVOID *buffer)
1580 {
1581 ASSERT(irp);
1582 ASSERT(buffer);
1583 ASSERT(bufferLength);
1584 ASSERT(requiredLength);
1585 if (!buffer || !irp || bufferLength == 0 || requiredLength == 0) {
1586 return STATUS_INVALID_PARAMETER;
1587 }
1588
1589 if (bufferLength < requiredLength) {
1590 return STATUS_NDIS_INVALID_LENGTH;
1591 }
1592 if (irp->MdlAddress == NULL) {
1593 return STATUS_INVALID_PARAMETER;
1594 }
1595 *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
1596 NormalPagePriority);
1597 if (*buffer == NULL) {
1598 return STATUS_INSUFFICIENT_RESOURCES;
1599 }
1600
1601 return STATUS_SUCCESS;
1602 }
1603
1604 /*
1605 * --------------------------------------------------------------------------
1606 * Utility function to fill up information about the state of a port in a reply
1607 * to* userspace.
1608 * --------------------------------------------------------------------------
1609 */
1610 static NTSTATUS
1611 OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1612 POVS_VPORT_EVENT_ENTRY eventEntry,
1613 PNL_BUFFER nlBuf)
1614 {
1615 NTSTATUS status;
1616 BOOLEAN ok;
1617 OVS_MESSAGE msgOutTmp;
1618 PNL_MSG_HDR nlMsg;
1619
1620 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && nlBuf->bufRemLen >= sizeof msgOutTmp);
1621
1622 msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_VPORT_FAMILY_ID;
1623 msgOutTmp.nlMsg.nlmsgFlags = 0; /* XXX: ? */
1624
1625 /* driver intiated messages should have zerp seq number*/
1626 msgOutTmp.nlMsg.nlmsgSeq = 0;
1627 msgOutTmp.nlMsg.nlmsgPid = usrParamsCtx->ovsInstance->pid;
1628
1629 msgOutTmp.genlMsg.version = nlVportFamilyOps.version;
1630 msgOutTmp.genlMsg.reserved = 0;
1631
1632 /* we don't have netdev yet, treat link up/down a adding/removing a port*/
1633 if (eventEntry->type & (OVS_EVENT_LINK_UP | OVS_EVENT_CONNECT)) {
1634 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_NEW;
1635 } else if (eventEntry->type &
1636 (OVS_EVENT_LINK_DOWN | OVS_EVENT_DISCONNECT)) {
1637 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_DEL;
1638 } else {
1639 ASSERT(FALSE);
1640 return STATUS_UNSUCCESSFUL;
1641 }
1642 msgOutTmp.ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
1643
1644 ok = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1645 if (!ok) {
1646 status = STATUS_INVALID_BUFFER_SIZE;
1647 goto cleanup;
1648 }
1649
1650 ok = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) &&
1651 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, eventEntry->ovsType) &&
1652 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_UPCALL_PID,
1653 eventEntry->upcallPid) &&
1654 NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, eventEntry->ovsName);
1655 if (!ok) {
1656 status = STATUS_INVALID_BUFFER_SIZE;
1657 goto cleanup;
1658 }
1659
1660 /* XXXX Should we add the port stats attributes?*/
1661 nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1662 nlMsg->nlmsgLen = NlBufSize(nlBuf);
1663 status = STATUS_SUCCESS;
1664
1665 cleanup:
1666 return status;
1667 }
1668
1669
1670 /*
1671 * --------------------------------------------------------------------------
1672 * Handler for reading events from the driver event queue. This handler is
1673 * executed when user modes issues a socket receive on a socket assocaited
1674 * with the MC group for events.
1675 * XXX user mode should read multiple events in one system call
1676 * --------------------------------------------------------------------------
1677 */
1678 static NTSTATUS
1679 OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1680 UINT32 *replyLen)
1681 {
1682 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1683 POVS_OPEN_INSTANCE instance =
1684 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1685 NL_BUFFER nlBuf;
1686 NTSTATUS status;
1687
1688 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1689
1690 /* Should never read events with a dump socket */
1691 ASSERT(instance->dumpState.ovsMsg == NULL);
1692
1693 /* Must have an event queue */
1694 ASSERT(instance->eventQueue != NULL);
1695
1696 /* Output buffer has been validated while validating read dev op. */
1697 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1698
1699 if (instance->protocol == NETLINK_NETFILTER) {
1700 if (!instance->mcastMask) {
1701 status = STATUS_SUCCESS;
1702 *replyLen = 0;
1703 goto cleanup;
1704 }
1705
1706 OVS_CT_EVENT_ENTRY ctEventEntry;
1707 status = OvsRemoveCtEventEntry(usrParamsCtx->ovsInstance,
1708 &ctEventEntry);
1709
1710 if (status != STATUS_SUCCESS) {
1711 /* If there were not elements, read should return no data. */
1712 status = STATUS_SUCCESS;
1713 *replyLen = 0;
1714 goto cleanup;
1715 }
1716
1717 /* Driver intiated messages should have zero seq number */
1718 status = OvsCreateNlMsgFromCtEntry(&ctEventEntry.entry,
1719 usrParamsCtx->outputBuffer,
1720 usrParamsCtx->outputLength,
1721 ctEventEntry.type,
1722 0, /* No input msg */
1723 usrParamsCtx->ovsInstance->pid,
1724 NFNETLINK_V0,
1725 gOvsSwitchContext->dpNo);
1726 if (status == NDIS_STATUS_SUCCESS) {
1727 *replyLen = msgOut->nlMsg.nlmsgLen;
1728 }
1729 } else if (instance->protocol == NETLINK_GENERIC) {
1730 NlBufInit(&nlBuf,
1731 usrParamsCtx->outputBuffer,
1732 usrParamsCtx->outputLength);
1733
1734 OVS_VPORT_EVENT_ENTRY eventEntry;
1735 /* remove vport event entry from the vport event queue */
1736 status = OvsRemoveVportEventEntry(usrParamsCtx->ovsInstance,
1737 &eventEntry);
1738 if (status != STATUS_SUCCESS) {
1739 /* If there were not elements, read should return no data. */
1740 status = STATUS_SUCCESS;
1741 *replyLen = 0;
1742 goto cleanup;
1743 }
1744
1745 status = OvsPortFillInfo(usrParamsCtx, &eventEntry, &nlBuf);
1746 if (status == NDIS_STATUS_SUCCESS) {
1747 *replyLen = NlBufSize(&nlBuf);
1748 }
1749 } else {
1750 status = STATUS_INVALID_PARAMETER;
1751 }
1752
1753 cleanup:
1754 return status;
1755 }
1756
1757 /*
1758 * --------------------------------------------------------------------------
1759 * Command Handler for 'OVS_CTRL_CMD_SOCK_PROP'.
1760 *
1761 * Handler to set and verify socket properties between userspace and kernel.
1762 *
1763 * Protocol is passed down by the userspace. It refers to the NETLINK family
1764 * and could be of different types (NETLINK_GENERIC/NETLINK_NETFILTER etc.,)
1765 * This function parses out the protocol and adds it to the open instance.
1766 *
1767 * PID is generated by the kernel and is set in userspace after querying the
1768 * kernel for it. This function does not modify PID set in the kernel,
1769 * instead it verifies if it was sent down correctly.
1770 *
1771 * XXX -This method can be modified to handle all Socket properties thereby
1772 * eliminating the use of OVS_IOCTL_GET_PID
1773 *
1774 * --------------------------------------------------------------------------
1775 */
1776 static NTSTATUS
1777 OvsSockPropCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1778 UINT32 *replyLen)
1779 {
1780 static const NL_POLICY ovsSocketPolicy[] = {
1781 [OVS_NL_ATTR_SOCK_PROTO] = { .type = NL_A_U32, .optional = TRUE },
1782 [OVS_NL_ATTR_SOCK_PID] = { .type = NL_A_U32, .optional = TRUE }
1783 };
1784 PNL_ATTR attrs[ARRAY_SIZE(ovsSocketPolicy)];
1785
1786 if (usrParamsCtx->outputLength < sizeof(OVS_MESSAGE)) {
1787 return STATUS_NDIS_INVALID_LENGTH;
1788 }
1789
1790 NL_BUFFER nlBuf;
1791 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1792 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1793 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1794 UINT32 protocol;
1795 PNL_MSG_HDR nlMsg;
1796 UINT32 pid;
1797
1798 /* Parse the input */
1799 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1800 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1801 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1802 ovsSocketPolicy,
1803 ARRAY_SIZE(ovsSocketPolicy),
1804 attrs,
1805 ARRAY_SIZE(attrs))) {
1806 return STATUS_INVALID_PARAMETER;
1807 }
1808
1809 /* Set the Protocol if it was passed down */
1810 if (attrs[OVS_NL_ATTR_SOCK_PROTO]) {
1811 protocol = NlAttrGetU32(attrs[OVS_NL_ATTR_SOCK_PROTO]);
1812 if (protocol) {
1813 instance->protocol = protocol;
1814 }
1815 }
1816
1817 /* Verify if the PID sent down matches the kernel */
1818 if (attrs[OVS_NL_ATTR_SOCK_PID]) {
1819 pid = NlAttrGetU32(attrs[OVS_NL_ATTR_SOCK_PID]);
1820 if (pid != instance->pid) {
1821 OVS_LOG_ERROR("Received invalid pid:%d expected:%d",
1822 pid, instance->pid);
1823 return STATUS_INVALID_PARAMETER;
1824 }
1825 }
1826
1827 /* Prepare the output */
1828 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1829 if(!NlFillOvsMsg(&nlBuf, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1830 msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1831 msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1832 gOvsSwitchContext->dpNo)){
1833 return STATUS_INVALID_BUFFER_SIZE;
1834 }
1835
1836 if (!NlMsgPutTailU32(&nlBuf, OVS_NL_ATTR_SOCK_PID,
1837 instance->pid)) {
1838 return STATUS_INVALID_BUFFER_SIZE;
1839 }
1840
1841 if (!NlMsgPutTailU32(&nlBuf, OVS_NL_ATTR_SOCK_PROTO,
1842 instance->protocol)) {
1843 return STATUS_INVALID_BUFFER_SIZE;
1844 }
1845
1846 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
1847 nlMsg->nlmsgLen = NlBufSize(&nlBuf);
1848 *replyLen = msgOut->nlMsg.nlmsgLen;
1849
1850 return STATUS_SUCCESS;
1851 }