]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/Datapath.c
datapath-windows: Add annotations for OvsAcquireCtrlLock
[mirror_ovs.git] / datapath-windows / ovsext / Datapath.c
CommitLineData
4f3988e0
NR
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 */
4f3988e0
NR
23
24#include "precomp.h"
ae1fd386
EE
25#include "Switch.h"
26#include "User.h"
3b89ffba 27#include "Datapath.h"
fa1324c9 28#include "Event.h"
fa1324c9
SG
29#include "NetProto.h"
30#include "Flow.h"
4f3988e0
NR
31
32#ifdef OVS_DBG_MOD
33#undef OVS_DBG_MOD
34#endif
35#define OVS_DBG_MOD OVS_DBG_DATAPATH
fa1324c9 36#include "Debug.h"
4f3988e0
NR
37
38#define NETLINK_FAMILY_NAME_LEN 48
39
3b89ffba
NR
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 */
7f9381db
EE
62typedef NTSTATUS(NetlinkCmdHandler)(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
63 UINT32 *replyLen);
3b89ffba
NR
64
65typedef struct _NETLINK_CMD {
66 UINT16 cmd;
7f9381db 67 NetlinkCmdHandler *handler;
3b89ffba 68 UINT32 supportedDevOp; /* Supported device operations. */
a19f14a7 69 BOOLEAN validateDpIndex; /* Does command require a valid DP argument. */
3b89ffba
NR
70} NETLINK_CMD, *PNETLINK_CMD;
71
72/* A netlink family is a group of commands. */
73typedef struct _NETLINK_FAMILY {
74 CHAR *name;
a51a5086 75 UINT16 id;
a19f14a7 76 UINT8 version;
a51a5086 77 UINT8 pad1;
3b89ffba 78 UINT16 maxAttr;
a51a5086 79 UINT16 pad2;
3b89ffba
NR
80 NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
81 UINT16 opsCount;
82} NETLINK_FAMILY, *PNETLINK_FAMILY;
83
3b89ffba 84/* Handlers for the various netlink commands. */
190cf533 85static NetlinkCmdHandler OvsPendEventCmdHandler,
d1d4a511 86 OvsSubscribeEventCmdHandler,
531bee45 87 OvsReadEventCmdHandler,
df4879cd 88 OvsNewDpCmdHandler,
2b144cbb 89 OvsGetDpCmdHandler,
e70f55ed
SV
90 OvsSetDpCmdHandler,
91 OvsSockPropCmdHandler;
012b5d13
NR
92
93NetlinkCmdHandler OvsGetNetdevCmdHandler,
8d9f1e0c 94 OvsGetVportCmdHandler,
11689acc 95 OvsSetVportCmdHandler,
611531c1 96 OvsNewVportCmdHandler,
6375650a
NR
97 OvsDeleteVportCmdHandler,
98 OvsPendPacketCmdHandler,
99 OvsSubscribePacketCmdHandler,
78f31c2b 100 OvsReadPacketCmdHandler,
2e4bd7a1
SV
101 OvsCtDeleteCmdHandler,
102 OvsCtDumpCmdHandler;
d1d4a511
NR
103
104static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
105 UINT32 *replyLen);
106static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
107 UINT32 *replyLen);
df4879cd
NR
108static NTSTATUS HandleDpTransactionCommon(
109 POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen);
190cf533
SV
110static NTSTATUS OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
111 UINT32 *replyLen);
63520eeb 112
3b89ffba
NR
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. */
121NETLINK_CMD nlControlFamilyCmdOps[] = {
7f9381db
EE
122 { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
123 .handler = OvsPendEventCmdHandler,
124 .supportedDevOp = OVS_WRITE_DEV_OP,
125 .validateDpIndex = TRUE,
126 },
f73dc821
EE
127 { .cmd = OVS_CTRL_CMD_WIN_PEND_PACKET_REQ,
128 .handler = OvsPendPacketCmdHandler,
129 .supportedDevOp = OVS_WRITE_DEV_OP,
130 .validateDpIndex = TRUE,
131 },
7f9381db
EE
132 { .cmd = OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
133 .handler = OvsSubscribeEventCmdHandler,
134 .supportedDevOp = OVS_WRITE_DEV_OP,
135 .validateDpIndex = TRUE,
531bee45 136 },
ae1fd386
EE
137 { .cmd = OVS_CTRL_CMD_PACKET_SUBSCRIBE_REQ,
138 .handler = OvsSubscribePacketCmdHandler,
139 .supportedDevOp = OVS_WRITE_DEV_OP,
140 .validateDpIndex = TRUE,
141 },
531bee45
EE
142 { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
143 .handler = OvsReadEventCmdHandler,
a51a5086 144 .supportedDevOp = OVS_READ_DEV_OP,
531bee45 145 .validateDpIndex = FALSE,
0d2cb708
EE
146 },
147 { .cmd = OVS_CTRL_CMD_READ_NOTIFY,
148 .handler = OvsReadPacketCmdHandler,
a51a5086 149 .supportedDevOp = OVS_READ_DEV_OP,
0d2cb708 150 .validateDpIndex = FALSE,
e70f55ed
SV
151 },
152 { .cmd = OVS_CTRL_CMD_SOCK_PROP,
153 .handler = OvsSockPropCmdHandler,
154 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
155 .validateDpIndex = FALSE,
0173bf06 156 }
3b89ffba
NR
157};
158
159NETLINK_FAMILY nlControlFamilyOps = {
a19f14a7
NR
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)
3b89ffba
NR
166};
167
63520eeb
NR
168/* Netlink datapath family. */
169NETLINK_CMD nlDatapathFamilyCmdOps[] = {
df4879cd
NR
170 { .cmd = OVS_DP_CMD_NEW,
171 .handler = OvsNewDpCmdHandler,
172 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
173 .validateDpIndex = FALSE
174 },
0173bf06
NR
175 { .cmd = OVS_DP_CMD_GET,
176 .handler = OvsGetDpCmdHandler,
d1d4a511
NR
177 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
178 OVS_TRANSACTION_DEV_OP,
90439167 179 .validateDpIndex = FALSE
d1d4a511
NR
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
0173bf06 186 }
63520eeb 187};
3b89ffba 188
63520eeb
NR
189NETLINK_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};
3b89ffba
NR
197
198/* Netlink packet family. */
094a1315
AS
199
200NETLINK_CMD nlPacketFamilyCmdOps[] = {
201 { .cmd = OVS_PACKET_CMD_EXECUTE,
202 .handler = OvsNlExecuteCmdHandler,
203 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
204 .validateDpIndex = TRUE
205 }
206};
207
3b89ffba 208NETLINK_FAMILY nlPacketFamilyOps = {
a19f14a7
NR
209 .name = OVS_PACKET_FAMILY,
210 .id = OVS_WIN_NL_PACKET_FAMILY_ID,
211 .version = OVS_PACKET_VERSION,
212 .maxAttr = OVS_PACKET_ATTR_MAX,
094a1315
AS
213 .cmds = nlPacketFamilyCmdOps,
214 .opsCount = ARRAY_SIZE(nlPacketFamilyCmdOps)
3b89ffba
NR
215};
216
3b89ffba 217/* Netlink vport family. */
17c6a05f
SG
218NETLINK_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
8d9f1e0c
NR
224 },
225 { .cmd = OVS_VPORT_CMD_NEW,
226 .handler = OvsNewVportCmdHandler,
227 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
228 .validateDpIndex = TRUE
611531c1 229 },
11689acc
NR
230 { .cmd = OVS_VPORT_CMD_SET,
231 .handler = OvsSetVportCmdHandler,
232 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
233 .validateDpIndex = TRUE
234 },
611531c1
NR
235 { .cmd = OVS_VPORT_CMD_DEL,
236 .handler = OvsDeleteVportCmdHandler,
237 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
238 .validateDpIndex = TRUE
239 },
17c6a05f
SG
240};
241
3b89ffba 242NETLINK_FAMILY nlVportFamilyOps = {
a19f14a7
NR
243 .name = OVS_VPORT_FAMILY,
244 .id = OVS_WIN_NL_VPORT_FAMILY_ID,
245 .version = OVS_VPORT_VERSION,
246 .maxAttr = OVS_VPORT_ATTR_MAX,
17c6a05f
SG
247 .cmds = nlVportFamilyCmdOps,
248 .opsCount = ARRAY_SIZE(nlVportFamilyCmdOps)
3b89ffba
NR
249};
250
251/* Netlink flow family. */
0d9bd68b
AS
252
253NETLINK_CMD nlFlowFamilyCmdOps[] = {
254 { .cmd = OVS_FLOW_CMD_NEW,
0679122d 255 .handler = OvsFlowNlCmdHandler,
0d9bd68b
AS
256 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
257 .validateDpIndex = TRUE
22b6623a 258 },
90439167 259 { .cmd = OVS_FLOW_CMD_SET,
0679122d 260 .handler = OvsFlowNlCmdHandler,
22b6623a 261 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
6247bec1
AS
262 .validateDpIndex = TRUE
263 },
264 { .cmd = OVS_FLOW_CMD_DEL,
0679122d 265 .handler = OvsFlowNlCmdHandler,
6247bec1
AS
266 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
267 .validateDpIndex = TRUE
90439167
AS
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 },
0d9bd68b
AS
275};
276
3b89ffba 277NETLINK_FAMILY nlFLowFamilyOps = {
a19f14a7
NR
278 .name = OVS_FLOW_FAMILY,
279 .id = OVS_WIN_NL_FLOW_FAMILY_ID,
280 .version = OVS_FLOW_VERSION,
281 .maxAttr = OVS_FLOW_ATTR_MAX,
0d9bd68b
AS
282 .cmds = nlFlowFamilyCmdOps,
283 .opsCount = ARRAY_SIZE(nlFlowFamilyCmdOps)
3b89ffba
NR
284};
285
78f31c2b
SV
286/* Netlink Ct family. */
287NETLINK_CMD nlCtFamilyCmdOps[] = {
288 { .cmd = IPCTNL_MSG_CT_DELETE,
289 .handler = OvsCtDeleteCmdHandler,
290 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
2e4bd7a1
SV
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
78f31c2b
SV
297 }
298};
299
300NETLINK_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
2b144cbb
NR
309/* Netlink netdev family. */
310NETLINK_CMD nlNetdevFamilyCmdOps[] = {
311 { .cmd = OVS_WIN_NETDEV_CMD_GET,
312 .handler = OvsGetNetdevCmdHandler,
313 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
314 .validateDpIndex = FALSE
315 },
316};
317
318NETLINK_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
63520eeb
NR
327static NTSTATUS MapIrpOutputBuffer(PIRP irp,
328 UINT32 bufferLength,
329 UINT32 requiredLength,
330 PVOID *buffer);
331static NTSTATUS ValidateNetlinkCmd(UINT32 devOp,
332 POVS_OPEN_INSTANCE instance,
333 POVS_MESSAGE ovsMsg,
e6b298ef 334 UINT32 ovsMgsLength,
63520eeb
NR
335 NETLINK_FAMILY *nlFamilyOps);
336static NTSTATUS InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
337 NETLINK_FAMILY *nlFamilyOps,
338 UINT32 *replyLen);
3b89ffba 339
4f3988e0
NR
340/* Handles to the device object for communication with userspace. */
341NDIS_HANDLE gOvsDeviceHandle;
342PDEVICE_OBJECT gOvsDeviceObject;
343
344_Dispatch_type_(IRP_MJ_CREATE)
345_Dispatch_type_(IRP_MJ_CLOSE)
346DRIVER_DISPATCH OvsOpenCloseDevice;
347
348_Dispatch_type_(IRP_MJ_CLEANUP)
349DRIVER_DISPATCH OvsCleanupDevice;
350
351_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
352DRIVER_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
3b89ffba
NR
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
63520eeb 366#define OVS_SYSTEM_DP_NAME "ovs-system"
4f3988e0
NR
367
368POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
369UINT32 ovsNumberOfOpenInstances;
370extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
371
372NDIS_SPIN_LOCK ovsCtrlLockObj;
373PNDIS_SPIN_LOCK gOvsCtrlLock;
374
5bf61915
SV
375NTSTATUS
376InitUserDumpState(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
397VOID
398FreeUserDumpState(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}
4f3988e0 406
811c911f 407NDIS_STATUS
4f3988e0
NR
408OvsInit()
409{
811c911f
SV
410 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
411
4f3988e0
NR
412 gOvsCtrlLock = &ovsCtrlLockObj;
413 NdisAllocateSpinLock(gOvsCtrlLock);
414 OvsInitEventQueue();
811c911f
SV
415
416 status = OvsPerCpuDataInit();
417
418 return status;
4f3988e0
NR
419}
420
421VOID
422OvsCleanup()
423{
811c911f 424 OvsPerCpuDataCleanup();
4f3988e0
NR
425 OvsCleanupEventQueue();
426 if (gOvsCtrlLock) {
427 NdisFreeSpinLock(gOvsCtrlLock);
428 gOvsCtrlLock = NULL;
429 }
4f3988e0
NR
430}
431
9f6573fe 432_Use_decl_annotations_
4f3988e0
NR
433VOID
434OvsAcquireCtrlLock()
435{
436 NdisAcquireSpinLock(gOvsCtrlLock);
437}
438
439VOID
440OvsReleaseCtrlLock()
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 */
452NDIS_STATUS
453OvsCreateDeviceObject(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);
d130ac9e 488 if (status == NDIS_STATUS_SUCCESS) {
59a33335 489 OvsRegisterSystemProvider((PVOID)gOvsDeviceObject);
d130ac9e
NR
490 } else {
491 OVS_LOG_ERROR("Failed to regiser pseudo device, error: 0x%08x",
492 status);
4f3988e0 493 }
448d667b 494
4f3988e0
NR
495 OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
496 return status;
497}
498
499
500VOID
501OvsDeleteDeviceObject()
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;
59a33335
SV
516
517 OvsUnregisterSystemProvider();
4f3988e0 518 }
4f3988e0
NR
519}
520
521POVS_OPEN_INSTANCE
522OvsGetOpenInstance(PFILE_OBJECT fileObject,
523 UINT32 dpNo)
524{
32654528 525 LOCK_STATE_EX lockState;
4f3988e0
NR
526 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
527 ASSERT(instance);
528 ASSERT(instance->fileObject == fileObject);
32654528
SV
529 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
530
d07ac93e 531 if (gOvsSwitchContext->dpNo != dpNo) {
32654528 532 instance = NULL;
4f3988e0 533 }
32654528
SV
534
535 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
4f3988e0
NR
536 return instance;
537}
538
539
540POVS_OPEN_INSTANCE
541OvsFindOpenInstance(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
556NTSTATUS
3b89ffba
NR
557OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
558 PFILE_OBJECT fileObject)
4f3988e0
NR
559{
560 POVS_OPEN_INSTANCE instance =
5bf61915
SV
561 (POVS_OPEN_INSTANCE)OvsAllocateMemoryWithTag(sizeof(OVS_OPEN_INSTANCE),
562 OVS_DATAPATH_POOL_TAG);
4f3988e0
NR
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();
5bf61915 573 OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
4f3988e0
NR
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;
5019855c 581 ovsNumberOfOpenInstances++;
4f3988e0
NR
582 instance->cookie = i;
583 break;
584 }
585 }
586 ASSERT(i < OVS_MAX_OPEN_INSTANCES);
587 instance->fileObject = fileObject;
588 ASSERT(fileObject->FsContext == NULL);
3b89ffba
NR
589 instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
590 if (instance->pid == 0) {
591 /* XXX: check for rollover. */
592 }
4f3988e0
NR
593 fileObject->FsContext = instance;
594 OvsReleaseCtrlLock();
595 return STATUS_SUCCESS;
596}
597
598static VOID
599OvsCleanupOpenInstance(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
608VOID
609OvsRemoveOpenInstance(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;
5019855c 620 ovsNumberOfOpenInstances--;
4f3988e0
NR
621 OvsReleaseCtrlLock();
622 ASSERT(instance->eventQueue == NULL);
623 ASSERT (instance->packetQueue == NULL);
216e1c14 624 FreeUserDumpState(instance);
5bf61915 625 OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
4f3988e0
NR
626}
627
628NTSTATUS
629OvsCompleteIrpRequest(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
640NTSTATUS
641OvsOpenCloseDevice(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
1919e76d 650#pragma warning(suppress: 28118)
12f1ba41 651 PAGED_CODE();
4f3988e0
NR
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:
3b89ffba 663 status = OvsAddOpenInstance(ovsExt, fileObject);
4f3988e0
NR
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_
680NTSTATUS
681OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
682 PIRP irp)
683{
1919e76d 684#pragma warning(suppress: 28118)
12f1ba41 685 PAGED_CODE();
4f3988e0
NR
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
4f3988e0
NR
710/*
711 * --------------------------------------------------------------------------
712 * IOCTL function handler for the device.
713 * --------------------------------------------------------------------------
714 */
715NTSTATUS
716OvsDeviceControl(PDEVICE_OBJECT deviceObject,
717 PIRP irp)
718{
4f3988e0
NR
719 PIO_STACK_LOCATION irpSp;
720 NTSTATUS status = STATUS_SUCCESS;
721 PFILE_OBJECT fileObject;
d838e577 722 PVOID inputBuffer = NULL;
3b89ffba 723 PVOID outputBuffer = NULL;
4f3988e0
NR
724 UINT32 inputBufferLen, outputBufferLen;
725 UINT32 code, replyLen = 0;
726 POVS_OPEN_INSTANCE instance;
3b89ffba
NR
727 UINT32 devOp;
728 OVS_MESSAGE ovsMsgReadOp;
729 POVS_MESSAGE ovsMsg;
e6b298ef 730 UINT32 ovsMsgLength = 0;
3b89ffba 731 NETLINK_FAMILY *nlFamilyOps;
e4bd84f3 732 OVS_USER_PARAMS_CONTEXT usrParamsCtx;
4f3988e0 733
1919e76d 734#pragma warning(suppress: 28118)
12f1ba41 735 PAGED_CODE();
4f3988e0
NR
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;
3b89ffba
NR
756 inputBuffer = irp->AssociatedIrp.SystemBuffer;
757
d07ac93e
SV
758 /* Check if the extension is enabled. */
759 if (NULL == gOvsSwitchContext) {
6c4e7adb
SV
760 status = STATUS_NOT_FOUND;
761 goto exit;
762 }
763
764 if (!OvsAcquireSwitchContext()) {
765 status = STATUS_NOT_FOUND;
766 goto exit;
d07ac93e
SV
767 }
768
3b89ffba
NR
769 /*
770 * Validate the input/output buffer arguments depending on the type of the
771 * operation.
772 */
773 switch (code) {
190cf533
SV
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
3b89ffba 792 case OVS_IOCTL_TRANSACT:
741224c9 793 /* Both input buffer and output buffer are mandatory. */
3b89ffba 794 if (outputBufferLen != 0) {
7e98ed23 795 ASSERT(sizeof(OVS_MESSAGE_ERROR) >= sizeof *ovsMsg);
3b89ffba 796 status = MapIrpOutputBuffer(irp, outputBufferLen,
7e98ed23
NR
797 sizeof(OVS_MESSAGE_ERROR),
798 &outputBuffer);
3b89ffba
NR
799 if (status != STATUS_SUCCESS) {
800 goto done;
801 }
802 ASSERT(outputBuffer);
741224c9
NR
803 } else {
804 status = STATUS_NDIS_INVALID_LENGTH;
805 goto done;
3b89ffba
NR
806 }
807
808 if (inputBufferLen < sizeof (*ovsMsg)) {
809 status = STATUS_NDIS_INVALID_LENGTH;
810 goto done;
811 }
4f3988e0 812
3b89ffba 813 ovsMsg = inputBuffer;
e6b298ef 814 ovsMsgLength = inputBufferLen;
3b89ffba
NR
815 devOp = OVS_TRANSACTION_DEV_OP;
816 break;
817
531bee45 818 case OVS_IOCTL_READ_EVENT:
0d2cb708 819 case OVS_IOCTL_READ_PACKET:
741224c9
NR
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 */
531bee45
EE
824 if (outputBufferLen != 0) {
825 status = MapIrpOutputBuffer(irp, outputBufferLen,
7e98ed23
NR
826 sizeof(OVS_MESSAGE_ERROR),
827 &outputBuffer);
531bee45
EE
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;
a51a5086
NR
840 RtlZeroMemory(ovsMsg, sizeof *ovsMsg);
841 ovsMsg->nlMsg.nlmsgLen = sizeof *ovsMsg;
842 ovsMsg->nlMsg.nlmsgType = nlControlFamilyOps.id;
deda30a9 843 ovsMsg->nlMsg.nlmsgPid = instance->pid;
a51a5086 844
531bee45 845 /* An "artificial" command so we can use NL family function table*/
0d2cb708
EE
846 ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
847 OVS_CTRL_CMD_EVENT_NOTIFY :
848 OVS_CTRL_CMD_READ_NOTIFY;
a51a5086 849 ovsMsg->genlMsg.version = nlControlFamilyOps.version;
e6b298ef 850 ovsMsgLength = outputBufferLen;
a51a5086 851
531bee45
EE
852 devOp = OVS_READ_DEV_OP;
853 break;
854
3b89ffba
NR
855 case OVS_IOCTL_READ:
856 /* Output buffer is mandatory. */
857 if (outputBufferLen != 0) {
858 status = MapIrpOutputBuffer(irp, outputBufferLen,
7e98ed23
NR
859 sizeof(OVS_MESSAGE_ERROR),
860 &outputBuffer);
3b89ffba
NR
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;
3b89ffba
NR
876
877 /*
878 * For implementing read (ioctl or otherwise), we need to store some
63520eeb
NR
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
21b83c6d 882 * appropriate handler. The handler itself can access the state in the
63520eeb 883 * instance.
3b89ffba 884 *
63520eeb 885 * In the absence of a dump start, return 0 bytes.
3b89ffba 886 */
63520eeb
NR
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;
e6b298ef 897 ovsMsgLength = sizeof (ovsMsgReadOp);
63520eeb 898 devOp = OVS_READ_DEV_OP;
3b89ffba
NR
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;
e6b298ef 910 ovsMsgLength = inputBufferLen;
3b89ffba
NR
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);
d838e577 920 switch (ovsMsg->nlMsg.nlmsgType) {
2e4bd7a1 921 case NFNL_TYPE_CT_GET:
78f31c2b
SV
922 case NFNL_TYPE_CT_DEL:
923 nlFamilyOps = &nlCtFamilyOps;
924 break;
3b89ffba
NR
925 case OVS_WIN_NL_CTRL_FAMILY_ID:
926 nlFamilyOps = &nlControlFamilyOps;
927 break;
3b89ffba 928 case OVS_WIN_NL_DATAPATH_FAMILY_ID:
63520eeb
NR
929 nlFamilyOps = &nlDatapathFamilyOps;
930 break;
3b89ffba 931 case OVS_WIN_NL_FLOW_FAMILY_ID:
0d9bd68b
AS
932 nlFamilyOps = &nlFLowFamilyOps;
933 break;
934 case OVS_WIN_NL_PACKET_FAMILY_ID:
094a1315
AS
935 nlFamilyOps = &nlPacketFamilyOps;
936 break;
17c6a05f
SG
937 case OVS_WIN_NL_VPORT_FAMILY_ID:
938 nlFamilyOps = &nlVportFamilyOps;
939 break;
2b144cbb
NR
940 case OVS_WIN_NL_NETDEV_FAMILY_ID:
941 nlFamilyOps = &nlNetdevFamilyOps;
942 break;
3b89ffba
NR
943 default:
944 status = STATUS_INVALID_PARAMETER;
945 goto done;
946 }
947
948 /*
a51a5086
NR
949 * For read operation, avoid duplicate validation since 'ovsMsg' is either
950 * "artificial" or was copied from a previously validated 'ovsMsg'.
3b89ffba
NR
951 */
952 if (devOp != OVS_READ_DEV_OP) {
e6b298ef
PB
953 status = ValidateNetlinkCmd(devOp, instance, ovsMsg,
954 ovsMsgLength, nlFamilyOps);
3b89ffba
NR
955 if (status != STATUS_SUCCESS) {
956 goto done;
957 }
958 }
959
e4bd84f3
NR
960 InitUserParamsCtx(irp, instance, devOp, ovsMsg,
961 inputBuffer, inputBufferLen,
962 outputBuffer, outputBufferLen,
963 &usrParamsCtx);
964
965 status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
3b89ffba
NR
966
967done:
6c4e7adb
SV
968 OvsReleaseSwitchContext(gOvsSwitchContext);
969
970exit:
5e82ceef 971 /* Should not complete a pending IRP unless proceesing is completed. */
8ddda685 972 if (status == STATUS_PENDING) {
cc84898c 973 return status;
8ddda685 974 }
4f3988e0
NR
975 return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
976}
977
3b89ffba
NR
978
979/*
980 * --------------------------------------------------------------------------
981 * Function to validate a netlink command. Only certain combinations of
982 * (device operation, netlink family, command) are valid.
983 * --------------------------------------------------------------------------
984 */
985static NTSTATUS
986ValidateNetlinkCmd(UINT32 devOp,
63520eeb 987 POVS_OPEN_INSTANCE instance,
3b89ffba 988 POVS_MESSAGE ovsMsg,
e6b298ef 989 UINT32 ovsMsgLength,
3b89ffba
NR
990 NETLINK_FAMILY *nlFamilyOps)
991{
992 NTSTATUS status = STATUS_INVALID_PARAMETER;
993 UINT16 i;
994
e6b298ef
PB
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
78f31c2b
SV
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
3b89ffba
NR
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
a19f14a7
NR
1039 /* Validate the DP for commands that require a DP. */
1040 if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
d07ac93e 1041 if (ovsMsg->ovsHdr.dp_ifindex !=
68501cfc 1042 (INT)gOvsSwitchContext->dpNo) {
3b89ffba 1043 status = STATUS_INVALID_PARAMETER;
3b89ffba
NR
1044 goto done;
1045 }
3b89ffba
NR
1046 }
1047
63520eeb 1048 /* Validate the PID. */
190cf533
SV
1049 if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
1050 status = STATUS_INVALID_PARAMETER;
1051 goto done;
63520eeb
NR
1052 }
1053
3b89ffba
NR
1054 status = STATUS_SUCCESS;
1055 break;
1056 }
1057 }
1058
e6b298ef
PB
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
3b89ffba
NR
1067done:
1068 return status;
1069}
1070
1071/*
1072 * --------------------------------------------------------------------------
a51a5086
NR
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.
3b89ffba
NR
1076 * --------------------------------------------------------------------------
1077 */
1078static NTSTATUS
e4bd84f3 1079InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
3b89ffba 1080 NETLINK_FAMILY *nlFamilyOps,
3b89ffba
NR
1081 UINT32 *replyLen)
1082{
1083 NTSTATUS status = STATUS_INVALID_PARAMETER;
1084 UINT16 i;
78f31c2b
SV
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 }
3b89ffba 1093
3b89ffba 1094 for (i = 0; i < nlFamilyOps->opsCount; i++) {
78f31c2b 1095 if (nlFamilyOps->cmds[i].cmd == cmd) {
7f9381db
EE
1096 NetlinkCmdHandler *handler = nlFamilyOps->cmds[i].handler;
1097 ASSERT(handler);
1098 if (handler) {
1099 status = handler(usrParamsCtx, replyLen);
1100 }
3b89ffba
NR
1101 break;
1102 }
1103 }
1104
a51a5086
NR
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);
8fd3ded1
NR
1122 OVS_MESSAGE msgInTmp = { 0 };
1123 POVS_MESSAGE msgIn = NULL;
a51a5086
NR
1124 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1125 usrParamsCtx->outputBuffer;
1126
78f31c2b
SV
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)) {
8fd3ded1
NR
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);
a51a5086 1141 ASSERT(msgError);
7e98ed23
NR
1142 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
1143 ASSERT(*replyLen != 0);
a51a5086
NR
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
3b89ffba
NR
1157 return status;
1158}
1159
3b89ffba
NR
1160/*
1161 * --------------------------------------------------------------------------
190cf533 1162 * Handler for 'OVS_IOCTL_GET_PID'.
d1d4a511 1163 *
3b89ffba 1164 * Each handle on the device is assigned a unique PID when the handle is
190cf533
SV
1165 * created. This function passes the PID to userspace using METHOD_BUFFERED
1166 * method.
3b89ffba
NR
1167 * --------------------------------------------------------------------------
1168 */
1169static NTSTATUS
190cf533
SV
1170OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1171 UINT32 *replyLen)
3b89ffba 1172{
190cf533
SV
1173 NTSTATUS status = STATUS_SUCCESS;
1174 PUINT32 msgOut = (PUINT32)usrParamsCtx->outputBuffer;
3b89ffba 1175
e4bd84f3
NR
1176 if (usrParamsCtx->outputLength >= sizeof *msgOut) {
1177 POVS_OPEN_INSTANCE instance =
1178 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
3b89ffba
NR
1179
1180 RtlZeroMemory(msgOut, sizeof *msgOut);
190cf533 1181 RtlCopyMemory(msgOut, &instance->pid, sizeof(*msgOut));
3b89ffba 1182 *replyLen = sizeof *msgOut;
3b89ffba 1183 } else {
190cf533
SV
1184 *replyLen = sizeof *msgOut;
1185 status = STATUS_NDIS_INVALID_LENGTH;
3b89ffba
NR
1186 }
1187
190cf533 1188 return status;
3b89ffba
NR
1189}
1190
3245c498
NR
1191/*
1192 * --------------------------------------------------------------------------
1193 * Utility function to fill up information about the datapath in a reply to
1194 * userspace.
3245c498
NR
1195 * --------------------------------------------------------------------------
1196 */
1197static NTSTATUS
1198OvsDpFillInfo(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
ffa08087 1207 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && NlBufRemLen(nlBuf) >= sizeof *msgIn);
3245c498
NR
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
7f9381db
EE
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 */
1248static NTSTATUS
1249OvsPendEventCmdHandler(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 */
1272static NTSTATUS
1273OvsSubscribeEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1274 UINT32 *replyLen)
1275{
1276 NDIS_STATUS status;
1277 OVS_EVENT_SUBSCRIBE request;
1278 BOOLEAN rc;
1279 UINT8 join;
1f3dd67f 1280 UINT32 mcastGrp;
7f9381db
EE
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 },
1f3dd67f 1285 };
7f9381db
EE
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
5b224954 1293 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
b8b00f0c
SV
1294 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, ARRAY_SIZE(policy),
1295 attrs, ARRAY_SIZE(attrs));
7f9381db
EE
1296 if (!rc) {
1297 status = STATUS_INVALID_PARAMETER;
1298 goto done;
1299 }
1300
1f3dd67f 1301 mcastGrp = NlAttrGetU32(attrs[OVS_NL_ATTR_MCAST_GRP]);
7f9381db
EE
1302 join = NlAttrGetU8(attrs[OVS_NL_ATTR_MCAST_JOIN]);
1303 request.dpNo = msgIn->ovsHdr.dp_ifindex;
1304 request.subscribe = join;
1f3dd67f
SV
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 }
6c6204b6
AK
1319 if (mcastGrp == NFNLGRP_CONNTRACK_UPDATE) {
1320 request.mask = OVS_EVENT_CT_UPDATE;
1321 }
1f3dd67f 1322 }
7f9381db
EE
1323
1324 status = OvsSubscribeEventIoctl(instance->fileObject, &request,
1325 sizeof request);
1326done:
1327 return status;
1328}
1329
df4879cd
NR
1330/*
1331 * --------------------------------------------------------------------------
1332 * Command Handler for 'OVS_DP_CMD_NEW'.
1333 * --------------------------------------------------------------------------
1334 */
1335static NTSTATUS
1336OvsNewDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1337 UINT32 *replyLen)
1338{
1339 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1340}
7f9381db 1341
63520eeb
NR
1342/*
1343 * --------------------------------------------------------------------------
d1d4a511
NR
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.
63520eeb
NR
1350 * --------------------------------------------------------------------------
1351 */
1352static NTSTATUS
1353OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1354 UINT32 *replyLen)
d1d4a511
NR
1355{
1356 if (usrParamsCtx->devOp == OVS_TRANSACTION_DEV_OP) {
df4879cd 1357 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
d1d4a511
NR
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 */
1368static NTSTATUS
1369HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1370 UINT32 *replyLen)
1371{
df4879cd 1372 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
d1d4a511
NR
1373}
1374
1375
1376/*
1377 * --------------------------------------------------------------------------
1378 * Function for handling the dump-based 'OVS_DP_CMD_GET' command.
1379 * --------------------------------------------------------------------------
1380 */
1381static NTSTATUS
1382HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1383 UINT32 *replyLen)
63520eeb 1384{
63520eeb
NR
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) {
0173bf06
NR
1390 *replyLen = 0;
1391 OvsSetupDumpStart(usrParamsCtx);
63520eeb 1392 } else {
3245c498
NR
1393 NL_BUFFER nlBuf;
1394 NTSTATUS status;
1395 POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
1396
63520eeb
NR
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);
741224c9 1406
63520eeb
NR
1407 /* Output buffer has been validated while validating read dev op. */
1408 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1409
3245c498
NR
1410 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
1411 usrParamsCtx->outputLength);
63520eeb 1412
3245c498 1413 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
63520eeb 1414
3245c498
NR
1415 if (status != STATUS_SUCCESS) {
1416 *replyLen = 0;
1417 FreeUserDumpState(instance);
1418 return status;
63520eeb 1419 }
63520eeb
NR
1420
1421 /* Increment the dump index. */
1422 instance->dumpState.index[0] = 1;
1423 *replyLen = msgOut->nlMsg.nlmsgLen;
63520eeb
NR
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}
3b89ffba 1431
d1d4a511
NR
1432
1433/*
1434 * --------------------------------------------------------------------------
1435 * Command Handler for 'OVS_DP_CMD_SET'.
1436 * --------------------------------------------------------------------------
1437 */
1438static NTSTATUS
1439OvsSetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1440 UINT32 *replyLen)
1441{
df4879cd 1442 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
d1d4a511
NR
1443}
1444
1445/*
1446 * --------------------------------------------------------------------------
df4879cd
NR
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.
d1d4a511
NR
1452 * --------------------------------------------------------------------------
1453 */
1454static NTSTATUS
df4879cd
NR
1455HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1456 UINT32 *replyLen)
d1d4a511
NR
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;
df4879cd 1462 NL_ERROR nlError = NL_ERROR_SUCCESS;
d1d4a511
NR
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
aded80d5
SV
1470 UNREFERENCED_PARAMETER(msgOut);
1471
d1d4a511
NR
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. */
df4879cd
NR
1476 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET ||
1477 usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
d1d4a511
NR
1478 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1479 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
5b224954 1480 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
1481 ovsDatapathSetPolicy,
1482 ARRAY_SIZE(ovsDatapathSetPolicy),
1483 dpAttrs, ARRAY_SIZE(dpAttrs))) {
d1d4a511
NR
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
741224c9
NR
1497 /* Output buffer has been validated while validating transact dev op. */
1498 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1499
d1d4a511
NR
1500 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1501
d1d4a511 1502 if (dpAttrs[OVS_DP_ATTR_NAME] != NULL) {
d07ac93e 1503 if (!OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
d1d4a511 1504 OVS_SYSTEM_DP_NAME)) {
df4879cd
NR
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;
d1d4a511
NR
1513 goto cleanup;
1514 }
1515 } else if ((UINT32)msgIn->ovsHdr.dp_ifindex != gOvsSwitchContext->dpNo) {
df4879cd
NR
1516 nlError = NL_ERROR_NODEV;
1517 goto cleanup;
1518 }
1519
1520 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
df4879cd 1521 nlError = NL_ERROR_EXIST;
d1d4a511
NR
1522 goto cleanup;
1523 }
1524
1525 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
d1d4a511
NR
1526
1527 *replyLen = NlBufSize(&nlBuf);
1528
1529cleanup:
df4879cd
NR
1530 if (nlError != NL_ERROR_SUCCESS) {
1531 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1532 usrParamsCtx->outputBuffer;
1533
7e98ed23
NR
1534 ASSERT(msgError);
1535 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
1536 ASSERT(*replyLen != 0);
df4879cd
NR
1537 }
1538
1539 return STATUS_SUCCESS;
d1d4a511
NR
1540}
1541
1542
90439167 1543NTSTATUS
0173bf06
NR
1544OvsSetupDumpStart(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 */
21b83c6d 1563 FreeUserDumpState(instance);
0173bf06
NR
1564
1565 return InitUserDumpState(instance, msgIn);
1566}
1567
611531c1 1568
3b89ffba
NR
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 */
1575static NTSTATUS
1576MapIrpOutputBuffer(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
531bee45
EE
1604/*
1605 * --------------------------------------------------------------------------
1606 * Utility function to fill up information about the state of a port in a reply
1607 * to* userspace.
531bee45
EE
1608 * --------------------------------------------------------------------------
1609 */
1610static NTSTATUS
1611OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
b90984c4 1612 POVS_VPORT_EVENT_ENTRY eventEntry,
531bee45
EE
1613 PNL_BUFFER nlBuf)
1614{
1615 NTSTATUS status;
3100516a 1616 BOOLEAN ok;
531bee45
EE
1617 OVS_MESSAGE msgOutTmp;
1618 PNL_MSG_HDR nlMsg;
531bee45
EE
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*/
9be4a837 1633 if (eventEntry->type & (OVS_EVENT_LINK_UP | OVS_EVENT_CONNECT)) {
531bee45 1634 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_NEW;
9be4a837 1635 } else if (eventEntry->type &
531bee45
EE
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
3100516a
EE
1644 ok = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1645 if (!ok) {
531bee45
EE
1646 status = STATUS_INVALID_BUFFER_SIZE;
1647 goto cleanup;
1648 }
1649
3100516a 1650 ok = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) &&
9be4a837 1651 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, eventEntry->ovsType) &&
3100516a 1652 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_UPCALL_PID,
9be4a837
NR
1653 eventEntry->upcallPid) &&
1654 NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, eventEntry->ovsName);
3100516a 1655 if (!ok) {
531bee45
EE
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
1665cleanup:
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 */
1678static NTSTATUS
1679OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1680 UINT32 *replyLen)
1681{
531bee45
EE
1682 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1683 POVS_OPEN_INSTANCE instance =
1684 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
531bee45
EE
1685 NL_BUFFER nlBuf;
1686 NTSTATUS status;
531bee45
EE
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
9c16b941
SV
1699 if (instance->protocol == NETLINK_NETFILTER) {
1700 if (!instance->mcastMask) {
1701 status = STATUS_SUCCESS;
1702 *replyLen = 0;
1703 goto cleanup;
1704 }
531bee45 1705
9c16b941
SV
1706 OVS_CT_EVENT_ENTRY ctEventEntry;
1707 status = OvsRemoveCtEventEntry(usrParamsCtx->ovsInstance,
1708 &ctEventEntry);
531bee45 1709
9c16b941
SV
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
4eb67d3f 1717 /* Driver intiated messages should have zero seq number */
9c16b941
SV
1718 status = OvsCreateNlMsgFromCtEntry(&ctEventEntry.entry,
1719 usrParamsCtx->outputBuffer,
1720 usrParamsCtx->outputLength,
1721 ctEventEntry.type,
4eb67d3f 1722 0, /* No input msg */
9c16b941
SV
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;
531bee45
EE
1751 }
1752
1753cleanup:
531bee45
EE
1754 return status;
1755}
e70f55ed
SV
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 */
1776static NTSTATUS
1777OvsSockPropCmdHandler(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}