kvm-guest-drivers-windows

Форк
0
1188 строк · 33.6 Кб
1
/*
2
 * Placeholder for the device related functions
3
 *
4
 * Copyright (c) 2019 Virtuozzo International GmbH
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met :
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and / or other materials provided with the distribution.
14
 * 3. Neither the names of the copyright holders nor the names of their contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

30
#include "precomp.h"
31
#include "viosock.h"
32

33
#if defined(EVENT_TRACING)
34
#include "Device.tmh"
35
#endif
36

37
EVT_WDF_DEVICE_PREPARE_HARDWARE     VIOSockEvtDevicePrepareHardware;
38
EVT_WDF_DEVICE_RELEASE_HARDWARE     VIOSockEvtDeviceReleaseHardware;
39
EVT_WDF_DEVICE_D0_ENTRY             VIOSockEvtDeviceD0Entry;
40
EVT_WDF_DEVICE_D0_EXIT              VIOSockEvtDeviceD0Exit;
41
EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED VIOSockEvtDeviceD0EntryPostInterruptsEnabled;
42
EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND          VIOSockEvtDeviceSelfManagedIoSuspend;
43
EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART          VIOSockEvtDeviceSelfManagedIoRestart;
44

45
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL  VIOSockEvtIoDeviceControl;
46
EVT_WDF_REQUEST_CANCEL              VIOSockSelectCancel;
47
EVT_WDF_WORKITEM                    VIOSockSelectWorkitem;
48
EVT_WDF_TIMER                       VIOSockSelectTimerFunc;
49

50
VOID
51
VIOSockQueuesCleanup(
52
    IN WDFDEVICE hDevice
53
);
54

55
NTSTATUS
56
VIOSockQueuesInit(
57
    IN WDFDEVICE hDevice
58
);
59

60
NTSTATUS
61
VIOSockDeviceGetConfig(
62
    IN WDFREQUEST   Request,
63
    OUT size_t      *pLength
64
);
65

66
NTSTATUS
67
VIOSockDeviceGetAf(
68
    IN WDFREQUEST   Request,
69
    OUT size_t      *pLength
70
);
71

72
typedef struct _VIOSOCK_SELECT_HANDLE
73
{
74
    ULONGLONG       hSocket;
75
    WDFFILEOBJECT   Socket;
76
}VIOSOCK_SELECT_HANDLE, *PVIOSOCK_SELECT_HANDLE;
77

78
typedef struct _VIOSOCK_SELECT_PKT
79
{
80
    LIST_ENTRY              ListEntry;
81
    LONGLONG                Timeout;
82
    PVIRTIO_VSOCK_SELECT    pSelect;
83
    ULONG                   FdCount[FDSET_MAX];
84
    NTSTATUS                Status;
85
    VIOSOCK_SELECT_HANDLE   Fds[FD_SETSIZE];
86
}VIOSOCK_SELECT_PKT, *PVIOSOCK_SELECT_PKT;
87

88
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(VIOSOCK_SELECT_PKT, GetSelectContext);
89

90
NTSTATUS
91
VIOSockSelectInit(
92
    IN PDEVICE_CONTEXT pContext
93
);
94

95
VOID
96
VIOSockSelectCleanupFds(
97
    IN PVIOSOCK_SELECT_PKT      pPkt,
98
    IN VIRTIO_VSOCK_FDSET_TYPE  iFdSet,
99
    IN ULONG                    uStartIndex
100
);
101

102
BOOLEAN
103
VIOSockSelectCheckPkt(
104
    IN PVIOSOCK_SELECT_PKT  pPkt
105
);
106

107
BOOLEAN
108
VIOSockSelectCopyFds(
109
    IN PDEVICE_CONTEXT          pContext,
110
    IN BOOLEAN                  bIs32BitProcess,
111
    IN PVIRTIO_VSOCK_SELECT     pSelect,
112
    IN PVIOSOCK_SELECT_PKT      pPkt,
113
    IN VIRTIO_VSOCK_FDSET_TYPE  iFdSet,
114
    IN ULONG                    uStartIndex
115
);
116

117
NTSTATUS
118
VIOSockSelect(
119
    IN WDFREQUEST Request,
120
    IN OUT size_t *pLength
121
);
122

123
#ifdef ALLOC_PRAGMA
124
#pragma alloc_text (PAGE, VIOSockEvtDeviceAdd)
125
#pragma alloc_text (PAGE, VIOSockQueuesCleanup)
126

127
#pragma alloc_text (PAGE, VIOSockEvtDevicePrepareHardware)
128
#pragma alloc_text (PAGE, VIOSockEvtDeviceReleaseHardware)
129
#pragma alloc_text (PAGE, VIOSockEvtDeviceD0Exit)
130
#pragma alloc_text (PAGE, VIOSockEvtDeviceSelfManagedIoSuspend)
131

132
#pragma alloc_text (PAGE, VIOSockDeviceGetConfig)
133
#pragma alloc_text (PAGE, VIOSockDeviceGetAf)
134
#pragma alloc_text (PAGE, VIOSockEvtIoDeviceControl)
135
#pragma alloc_text (PAGE, VIOSockSelectInit)
136
#pragma alloc_text (PAGE, VIOSockSelectCleanupFds)
137
#pragma alloc_text (PAGE, VIOSockSelectCheckPkt)
138
#pragma alloc_text (PAGE, VIOSockSelectWorkitem)
139
#pragma alloc_text (PAGE, VIOSockSelectCopyFds)
140
#pragma alloc_text (PAGE, VIOSockSelect)
141
#endif
142

143
static
144
VOID
145
VIOSockQueuesCleanup(
146
    IN WDFDEVICE hDevice
147
)
148
{
149
    PDEVICE_CONTEXT pContext = GetDeviceContext(hDevice);
150
    NTSTATUS status = STATUS_SUCCESS;
151

152
    ULONG uBufferSize;
153

154
    PAGED_CODE();
155

156
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
157

158
    if (pContext->RxVq)
159
        VIOSockRxVqCleanup(pContext);
160

161
    if (pContext->TxVq)
162
        VIOSockTxVqCleanup(pContext);
163

164
    if (pContext->EvtVq)
165
        VIOSockEvtVqCleanup(pContext);
166

167
    VirtIOWdfDestroyQueues(&pContext->VDevice);
168
}
169

170
static
171
NTSTATUS
172
VIOSockQueuesInit(
173
    IN WDFDEVICE hDevice
174
)
175
{
176
    PDEVICE_CONTEXT pContext = GetDeviceContext(hDevice);
177
    NTSTATUS status = STATUS_SUCCESS;
178
    VIRTIO_WDF_QUEUE_PARAM params[VIOSOCK_VQ_MAX];
179
    PVIOSOCK_VQ vqs[VIOSOCK_VQ_MAX];
180

181
    ULONG uBufferSize;
182

183
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
184

185
    // rx
186
    params[VIOSOCK_VQ_RX].Interrupt = pContext->WdfInterrupt;
187
    // tx
188
    params[VIOSOCK_VQ_TX].Interrupt = pContext->WdfInterrupt;
189
    // event
190
    params[VIOSOCK_VQ_EVT].Interrupt = pContext->WdfInterrupt;
191

192
    status = VirtIOWdfInitQueues(&pContext->VDevice, VIOSOCK_VQ_MAX, vqs, params);
193
    if (!NT_SUCCESS(status))
194
    {
195
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "VirtIOWdfInitQueues failed: 0x%x\n", status);
196
        return status;
197
    }
198

199
    pContext->RxVq = vqs[VIOSOCK_VQ_RX];
200
    status = VIOSockRxVqInit(pContext);
201
    if (NT_SUCCESS(status))
202
    {
203
        pContext->TxVq = vqs[VIOSOCK_VQ_TX];
204
        status = VIOSockTxVqInit(pContext);
205
        if (NT_SUCCESS(status))
206
        {
207
            pContext->EvtVq = vqs[VIOSOCK_VQ_EVT];
208
            status = VIOSockEvtVqInit(pContext);
209
            if (!NT_SUCCESS(status))
210
                pContext->EvtVq = NULL;
211
        }
212
        else
213
            pContext->TxVq = NULL;
214
    }
215
    else
216
        pContext->RxVq = NULL;
217

218
    if (!NT_SUCCESS(status))
219
        VIOSockQueuesCleanup(hDevice);
220

221
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
222

223
    return status;
224
}
225

226
//////////////////////////////////////////////////////////////////////////
227
NTSTATUS
228
VIOSockEvtDeviceAdd(
229
    IN WDFDRIVER Driver,
230
    IN PWDFDEVICE_INIT DeviceInit
231
)
232
{
233
    NTSTATUS                     status = STATUS_SUCCESS;
234
    WDF_OBJECT_ATTRIBUTES        Attributes;
235
    WDFDEVICE                    hDevice;
236
    WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;
237
    PDEVICE_CONTEXT              pContext = NULL;
238
    WDF_FILEOBJECT_CONFIG        fileConfig;
239
    WDF_IO_QUEUE_CONFIG          queueConfig;
240
    WDF_WORKITEM_CONFIG          wrkConfig;
241

242
    DECLARE_CONST_UNICODE_STRING(usDeviceName, VIOSOCK_DEVICE_NAME);
243
    DECLARE_CONST_UNICODE_STRING(usDosDeviceName, VIOSOCK_SYMLINK_NAME);
244

245
    UNREFERENCED_PARAMETER(Driver);
246

247
    PAGED_CODE();
248

249
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
250

251
    // Configure Pnp/power callbacks
252
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);
253
    PnpPowerCallbacks.EvtDevicePrepareHardware = VIOSockEvtDevicePrepareHardware;
254
    PnpPowerCallbacks.EvtDeviceReleaseHardware = VIOSockEvtDeviceReleaseHardware;
255
    PnpPowerCallbacks.EvtDeviceD0Entry         = VIOSockEvtDeviceD0Entry;
256
    PnpPowerCallbacks.EvtDeviceD0Exit          = VIOSockEvtDeviceD0Exit;
257
    PnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = VIOSockEvtDeviceD0EntryPostInterruptsEnabled;
258
    PnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = VIOSockEvtDeviceSelfManagedIoSuspend;
259
    PnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = VIOSockEvtDeviceSelfManagedIoRestart;
260
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks);
261

262
    // Set DirectIO mode
263
    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
264

265
    // Set device name (for kernel mode clients)
266
    status = WdfDeviceInitAssignName(DeviceInit, &usDeviceName);
267
    if (!NT_SUCCESS(status))
268
    {
269
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceInitAssignName failed - 0x%x\n", status);
270
        return status;
271
    }
272

273
    // Set device access (for user mode clients)
274
    status = WdfDeviceInitAssignSDDLString(DeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
275
    if (!NT_SUCCESS(status))
276
    {
277
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceInitAssignSDDLString failed - 0x%x\n", status);
278
        return status;
279
    }
280

281
    // Configure file object callbacks
282
    WDF_FILEOBJECT_CONFIG_INIT(
283
        &fileConfig,
284
        VIOSockCreateStub,
285
        WDF_NO_EVENT_CALLBACK, // Close
286
        VIOSockCleanup
287
    );
288
    fileConfig.FileObjectClass = WdfFileObjectWdfCanUseFsContext;
289

290
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, SOCKET_CONTEXT);
291

292
    WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, &Attributes);
293

294
    // Create device
295
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, DEVICE_CONTEXT);
296

297
    status = WdfDeviceCreate(&DeviceInit, &Attributes, &hDevice);
298
    if (!NT_SUCCESS(status))
299
    {
300
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreate failed - 0x%x\n", status);
301
        return status;
302
    }
303

304
    status = WdfDeviceCreateDeviceInterface(
305
        hDevice,
306
        &GUID_DEVINTERFACE_VIOSOCK,
307
        NULL
308
    );
309
    if (!NT_SUCCESS(status))
310
    {
311
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateDeviceInterface failed - 0x%x\n", status);
312
        return status;
313
    }
314

315
    status = WdfDeviceCreateSymbolicLink(
316
        hDevice,
317
        &usDosDeviceName
318
    );
319

320
    if (!NT_SUCCESS(status))
321
    {
322
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateSymbolicLink failed - 0x%x\n", status);
323
        return status;
324
    }
325

326
    status = VIOSockBoundListInit(hDevice);
327
    if (!NT_SUCCESS(status))
328
    {
329
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSockBoundListInit failed - 0x%x\n", status);
330
        return status;
331
    }
332

333
    status = VIOSockConnectedListInit(hDevice);
334
    if (!NT_SUCCESS(status))
335
    {
336
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSockConnectedListInit failed - 0x%x\n", status);
337
        return status;
338
    }
339

340
    pContext = GetDeviceContext(hDevice);
341

342
    pContext->ThisDevice = hDevice;
343

344
    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
345
    Attributes.ParentObject = hDevice;
346

347
    status = WdfLookasideListCreate(&Attributes,
348
        sizeof(VIOSOCK_ACCEPT_ENTRY), NonPagedPoolNx,
349
        &Attributes, VIOSOCK_DRIVER_MEMORY_TAG,
350
        &pContext->AcceptMemoryList);
351

352
    if (!NT_SUCCESS(status))
353
    {
354
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
355
            "WdfLookasideListCreate failed: 0x%x\n", status);
356
        return status;
357
    }
358

359
    // Create sequential queue for IoCtl requests
360
    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
361
        WdfIoQueueDispatchParallel
362
    );
363
    queueConfig.EvtIoDeviceControl = VIOSockEvtIoDeviceControl;
364
    queueConfig.AllowZeroLengthRequests = WdfFalse;
365

366
    status = WdfIoQueueCreate(hDevice,
367
        &queueConfig,
368
        WDF_NO_OBJECT_ATTRIBUTES,
369
        &pContext->IoCtlQueue
370
    );
371

372
    if (!NT_SUCCESS(status))
373
    {
374
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
375
            "WdfIoQueueCreate failed (IoCtrl Queue): 0x%x\n", status);
376
        return status;
377
    }
378

379
    status = WdfDeviceConfigureRequestDispatching(hDevice,
380
        pContext->IoCtlQueue,
381
        WdfRequestTypeDeviceControl);
382

383
    if (!NT_SUCCESS(status))
384
    {
385
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
386
            "WdfDeviceConfigureRequestDispatching failed (IoCtrl Queue): 0x%x\n", status);
387
        return status;
388
    }
389

390
    // Create parallel queue for Write requests
391
    status = VIOSockWriteQueueInit(hDevice);
392
    if (!NT_SUCCESS(status))
393
    {
394
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
395
            "VIOSockWriteQueueInit failed (Write Queue): 0x%x\n", status);
396
        return status;
397
    }
398

399
    // Create parallel queue for Read requests
400
    status = VIOSockReadQueueInit(hDevice);
401
    if (!NT_SUCCESS(status))
402
    {
403
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
404
            "VIOSockReadQueueInit failed (Read Queue): 0x%x\n", status);
405
        return status;
406
    }
407

408
    status = VIOSockSelectInit(pContext);
409
    if (!NT_SUCCESS(status))
410
    {
411
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
412
            "VIOSockSelectInit failed: 0x%x\n", status);
413
        return status;
414
    }
415

416
    status = VIOSockInterruptInit(hDevice);
417
    if(!NT_SUCCESS(status))
418
    {
419
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSockInterruptInit failed - 0x%x\n", status);
420
    }
421

422
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
423
    return status;
424
}
425

426
static
427
NTSTATUS
428
VIOSockEvtDevicePrepareHardware(
429
    IN WDFDEVICE Device,
430
    IN WDFCMRESLIST ResourcesRaw,
431
    IN WDFCMRESLIST ResourcesTranslated)
432
{
433
    PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
434
    NTSTATUS status = STATUS_SUCCESS;
435
    UINT nr_ports;
436
    u64 u64HostFeatures;
437
    u64 u64GuestFeatures = 0;
438

439
    UNREFERENCED_PARAMETER(ResourcesRaw);
440
    PAGED_CODE();
441

442
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
443

444
    status = VirtIOWdfInitialize(
445
        &pContext->VDevice,
446
        Device,
447
        ResourcesTranslated,
448
        NULL,
449
        VIOSOCK_DRIVER_MEMORY_TAG);
450
    if (!NT_SUCCESS(status))
451
    {
452
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "VirtIOWdfInitialize failed with 0x%x\n", status);
453
        return status;
454
    }
455

456
    u64HostFeatures = VirtIOWdfGetDeviceFeatures(&pContext->VDevice);
457

458
    if (virtio_is_feature_enabled(u64HostFeatures, VIRTIO_RING_F_INDIRECT_DESC))
459
    {
460
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "Enable indirect feature.\n");
461

462
        virtio_feature_enable(u64GuestFeatures, VIRTIO_RING_F_INDIRECT_DESC);
463
    }
464

465
    status = VirtIOWdfSetDriverFeatures(&pContext->VDevice, u64GuestFeatures, 0);
466
    if (!NT_SUCCESS(status))
467
    {
468
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "VirtIOWdfSetDriverFeatures failed: 0x%x\n", status);
469
        VirtIOWdfSetDriverFailed(&pContext->VDevice);
470
    }
471

472
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
473
    return status;
474
}
475

476
static
477
NTSTATUS
478
VIOSockEvtDeviceReleaseHardware(
479
    IN WDFDEVICE Device,
480
    IN WDFCMRESLIST ResourcesTranslated)
481
{
482
    PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
483

484
    UNREFERENCED_PARAMETER(ResourcesTranslated);
485
    PAGED_CODE();
486

487
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
488

489
    VirtIOWdfShutdown(&pContext->VDevice);
490

491
    return STATUS_SUCCESS;
492
}
493

494
static
495
NTSTATUS
496
VIOSockEvtDeviceD0Entry(
497
    IN  WDFDEVICE Device,
498
    IN  WDF_POWER_DEVICE_STATE PreviousState
499
)
500
{
501
    NTSTATUS status = STATUS_SUCCESS;
502
    PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
503

504
    UNREFERENCED_PARAMETER(PreviousState);
505

506
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> %s\n", __FUNCTION__);
507

508
    status = VIOSockQueuesInit(Device);
509
    if (!NT_SUCCESS(status))
510
    {
511
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIOSockQueuesInit failed: 0x%x\n", status);
512
        return status;
513
    }
514

515
    VirtIOWdfDeviceGet(&pContext->VDevice,
516
        0,
517
        &pContext->Config,
518
        sizeof(pContext->Config));
519

520
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
521
        "guest_cid %lld\n", pContext->Config.guest_cid);
522

523
    return status;
524
}
525

526
static
527
NTSTATUS
528
VIOSockEvtDeviceD0Exit(
529
    IN  WDFDEVICE Device,
530
    IN  WDF_POWER_DEVICE_STATE TargetState
531
    )
532
{
533
    PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
534

535
    PAGED_CODE();
536

537
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> %s TargetState: %d\n",
538
        __FUNCTION__, TargetState);
539

540
    VIOSockQueuesCleanup(Device);
541

542
    return STATUS_SUCCESS;
543
}
544

545
static
546
NTSTATUS
547
VIOSockEvtDeviceD0EntryPostInterruptsEnabled(
548
    IN  WDFDEVICE WdfDevice,
549
    IN  WDF_POWER_DEVICE_STATE PreviousState
550
    )
551
{
552
    PDEVICE_CONTEXT    pContext = GetDeviceContext(WdfDevice);
553
    UNREFERENCED_PARAMETER(PreviousState);
554

555
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);
556

557
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "Setting VIRTIO_CONFIG_S_DRIVER_OK flag\n");
558
    VirtIOWdfSetDriverOK(&pContext->VDevice);
559

560
    ASSERT(pContext->RxVq && pContext->EvtVq);
561

562
    return STATUS_SUCCESS;
563
}
564

565

566
NTSTATUS
567
VIOSockEvtDeviceSelfManagedIoSuspend(
568
    IN WDFDEVICE Device
569
)
570
{
571
    PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
572

573
    PAGED_CODE();
574

575
    VIOSockWriteIoSuspend(pContext);
576

577
    return STATUS_SUCCESS;
578
}
579

580
NTSTATUS
581
VIOSockEvtDeviceSelfManagedIoRestart(
582
    IN WDFDEVICE Device
583
)
584
{
585

586
    PDEVICE_CONTEXT pContext = GetDeviceContext(Device);
587

588
    VIOSockWriteIoRestart(pContext);
589

590
    return STATUS_SUCCESS;
591
}
592

593
static
594
NTSTATUS
595
VIOSockDeviceGetConfig(
596
    IN WDFREQUEST   Request,
597
    OUT size_t      *pLength
598
)
599
{
600
    PVIRTIO_VSOCK_CONFIG    pConfig = NULL;
601
    NTSTATUS                status;
602

603
    PAGED_CODE();
604

605
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s\n", __FUNCTION__);
606

607
    status = WdfRequestRetrieveOutputBuffer(Request, sizeof(VIRTIO_VSOCK_CONFIG), (PVOID*)&pConfig, pLength);
608
    if (!NT_SUCCESS(status))
609
    {
610
        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
611
            "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
612
        return status;
613
    }
614

615
    // minimum length guaranteed by WdfRequestRetrieveOutputBuffer above
616
    _Analysis_assume_(*pLength >= sizeof(VIRTIO_VSOCK_CONFIG));
617

618
    *pConfig = GetDeviceContextFromRequest(Request)->Config;
619
    *pLength = sizeof(*pConfig);
620

621
    return STATUS_SUCCESS;
622
}
623

624
static
625
NTSTATUS
626
VIOSockDeviceGetAf(
627
    IN WDFREQUEST   Request,
628
    OUT size_t      *pLength
629
)
630
{
631
    PULONG                  pulAF = NULL;
632
    NTSTATUS                status;
633

634
    PAGED_CODE();
635

636
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s\n", __FUNCTION__);
637

638
    status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*pulAF), (PVOID*)&pulAF, pLength);
639
    if (!NT_SUCCESS(status))
640
    {
641
        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
642
            "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
643
        return status;
644
    }
645

646
    // minimum length guaranteed by WdfRequestRetrieveOutputBuffer above
647
    _Analysis_assume_(*pLength >= sizeof(*pulAF));
648

649
    *pulAF = AF_VSOCK;
650
    *pLength = sizeof(*pulAF);
651

652
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s, AF: %d\n", __FUNCTION__, *pulAF);
653

654
    return STATUS_SUCCESS;
655
}
656

657
static
658
VOID
659
VIOSockEvtIoDeviceControl(
660
    IN WDFQUEUE   Queue,
661
    IN WDFREQUEST Request,
662
    IN size_t     OutputBufferLength,
663
    IN size_t     InputBufferLength,
664
    IN ULONG      IoControlCode
665
)
666
{
667
    size_t          Length = 0;
668
    NTSTATUS        status = STATUS_SUCCESS;
669

670
    PAGED_CODE();
671

672
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s\n", __FUNCTION__);
673

674
    switch (IoControlCode)
675
    {
676
    case IOCTL_GET_CONFIG:
677
        status = VIOSockDeviceGetConfig(Request, &Length);
678
        break;
679

680
    case IOCTL_SELECT:
681
        status = VIOSockSelect(Request, &Length);
682
        break;
683

684
    case IOCTL_GET_AF:
685
        status = VIOSockDeviceGetAf(Request, &Length);
686
        break;
687

688
    default:
689
        if (IsControlRequest(Request))
690
        {
691
            TraceEvents(TRACE_LEVEL_WARNING, DBG_IOCTLS, "Invalid socket type\n");
692
            status = STATUS_NOT_SOCKET;
693
        }
694
        else
695
        {
696
            status = VIOSockDeviceControl(
697
                Request,
698
                IoControlCode,
699
                &Length);
700
        }
701
    }
702

703
    if (status != STATUS_PENDING)
704
        WdfRequestCompleteWithInformation(Request, status, Length);
705

706
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s, status: 0x%08x\n", __FUNCTION__, status);
707
}
708

709
//////////////////////////////////////////////////////////////////////////
710
static
711
NTSTATUS
712
VIOSockSelectInit(
713
    IN PDEVICE_CONTEXT pContext
714
)
715
{
716
    NTSTATUS                status;
717
    WDF_OBJECT_ATTRIBUTES   Attributes;
718
    WDF_WORKITEM_CONFIG     wrkConfig;
719

720
    PAGED_CODE();
721

722
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
723

724
    InitializeListHead(&pContext->SelectList);
725
    pContext->SelectInProgress = 0;
726

727
    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
728
    Attributes.ParentObject = pContext->ThisDevice;
729

730
    status = WdfWaitLockCreate(&Attributes, &pContext->SelectLock);
731
    if (!NT_SUCCESS(status))
732
    {
733
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT,
734
            "WdfWaitLockCreate failed (Select): 0x%x\n", status);
735
        return status;
736
    }
737

738
    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
739
    Attributes.ParentObject = pContext->ThisDevice;
740

741
    WDF_WORKITEM_CONFIG_INIT(&wrkConfig, VIOSockSelectWorkitem);
742
    status = WdfWorkItemCreate(&wrkConfig, &Attributes, &pContext->SelectWorkitem);
743
    if (!NT_SUCCESS(status))
744
    {
745
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT,
746
            "WdfWorkItemCreate failed (Select): 0x%x\n", status);
747
        return status;
748
    }
749

750
    VIOSockTimerCreate(&pContext->SelectTimer, pContext->ThisDevice, VIOSockSelectTimerFunc);
751
    if (!NT_SUCCESS(status))
752
    {
753
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT,
754
            "VIOSockTimerCreate failed (Select): 0x%x\n", status);
755
    }
756

757
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "<-- %s\n", __FUNCTION__);
758

759
    return status;
760
}
761

762
static
763
VOID
764
VIOSockSelectCleanupFds(
765
    IN PVIOSOCK_SELECT_PKT      pPkt,
766
    IN VIRTIO_VSOCK_FDSET_TYPE  iFdSet,
767
    IN ULONG                    uStartIndex
768

769
)
770
{
771
    ULONG i;
772
    PVIOSOCK_SELECT_HANDLE  pHandleSet = &pPkt->Fds[uStartIndex];
773

774
    PAGED_CODE();
775

776
    for (i = 0; i < pPkt->FdCount[iFdSet]; ++i)
777
    {
778
        ASSERT(pHandleSet[i].Socket);
779

780
        InterlockedDecrement(&GetSocketContext(pHandleSet[i].Socket)->SelectRefs[iFdSet]); //dereference socket
781
        VioSockDereference(pHandleSet[i].Socket);
782
    }
783

784
    pPkt->FdCount[iFdSet] = 0;
785
}
786

787
__inline
788
VOID
789
VIOSockSelectCleanupPkt(
790
    IN PVIOSOCK_SELECT_PKT pPkt
791
)
792
{
793
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s, status: 0x%08x\n", __FUNCTION__, pPkt->Status);
794

795
    VIOSockSelectCleanupFds(pPkt, FDSET_READ, 0);
796
    VIOSockSelectCleanupFds(pPkt, FDSET_WRITE, pPkt->FdCount[FDSET_READ]);
797
    VIOSockSelectCleanupFds(pPkt, FDSET_EXCPT, pPkt->FdCount[FDSET_READ] + pPkt->FdCount[FDSET_WRITE]);
798
}
799

800
static
801
VOID
802
VIOSockSelectTimerFunc(
803
    IN WDFTIMER Timer
804
)
805
{
806
    PDEVICE_CONTEXT pContext = GetDeviceContext(WdfTimerGetParentObject(Timer));
807

808
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
809

810
    if (InterlockedIncrement(&pContext->SelectInProgress) == 1)
811
    {
812
        WdfWorkItemEnqueue(pContext->SelectWorkitem);
813
    }
814
}
815

816
static
817
BOOLEAN
818
VIOSockSelectCheckPkt(
819
    IN PVIOSOCK_SELECT_PKT  pPkt
820
)
821
{
822
    ULONG i;
823
    PVIOSOCK_SELECT_HANDLE  pHandleSet;
824
    PVIRTIO_VSOCK_FD_SET    pFds;
825

826
    PAGED_CODE();
827

828
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
829

830
    pFds = &pPkt->pSelect->Fdss[FDSET_READ];
831
    pHandleSet = pPkt->Fds;
832

833
    pFds->fd_count = 0;
834
    for (i = 0; i < pPkt->FdCount[FDSET_READ]; ++i)
835
    {
836
        PSOCKET_CONTEXT pSocket = GetSocketContext(pHandleSet[i].Socket);
837
        if (pSocket->Events & (FD_ACCEPT | FD_READ | FD_CLOSE))
838
        {
839
            pFds->fd_array[pFds->fd_count++] = pHandleSet[i].hSocket;
840
        }
841
    }
842

843
    pFds = &pPkt->pSelect->Fdss[FDSET_WRITE];
844
    pHandleSet = &pPkt->Fds[pPkt->FdCount[FDSET_READ]];
845

846
    pFds->fd_count = 0;
847
    for (i = 0; i < pPkt->FdCount[FDSET_WRITE]; ++i)
848
    {
849
        PSOCKET_CONTEXT pSocket = GetSocketContext(pHandleSet[i].Socket);
850
        if (pSocket->Events & FD_WRITE ||
851
            (pSocket->Events & FD_CONNECT) && NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]))
852
        {
853
            pFds->fd_array[pFds->fd_count++] = pHandleSet[i].hSocket;
854
        }
855
    }
856

857
    pFds = &pPkt->pSelect->Fdss[FDSET_EXCPT];
858
    pHandleSet = &pPkt->Fds[pPkt->FdCount[FDSET_READ] + pPkt->FdCount[FDSET_WRITE]];
859

860
    pFds->fd_count = 0;
861
    for (i = 0; i < pPkt->FdCount[FDSET_EXCPT]; ++i)
862
    {
863
        PSOCKET_CONTEXT pSocket = GetSocketContext(pHandleSet[i].Socket);
864
        if ((pSocket->Events & FD_CONNECT) &&
865
            !NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]))
866
        {
867
            pFds->fd_array[pFds->fd_count++] = pHandleSet[i].hSocket;
868
        }
869
    }
870

871
    return pPkt->pSelect->Fdss[FDSET_READ].fd_count ||
872
        pPkt->pSelect->Fdss[FDSET_WRITE].fd_count ||
873
        pPkt->pSelect->Fdss[FDSET_EXCPT].fd_count;
874
}
875

876
static
877
VOID
878
VIOSockSelectCancel(
879
    IN WDFREQUEST Request
880
)
881
{
882
    PDEVICE_CONTEXT pContext = GetDeviceContextFromRequest(Request);
883

884
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
885

886
    if (InterlockedIncrement(&pContext->SelectInProgress) == 1)
887
    {
888
        WdfWorkItemEnqueue(pContext->SelectWorkitem);
889
    }
890
}
891

892
static
893
VOID
894
VIOSockSelectWorkitem(
895
    IN WDFWORKITEM Workitem
896
)
897
{
898
    PDEVICE_CONTEXT pContext = GetDeviceContext(WdfWorkItemGetParentObject(Workitem));
899

900
    PAGED_CODE();
901

902
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
903

904
    do
905
    {
906
        LIST_ENTRY  CompletionList;
907
        WDFREQUEST  Request;
908
        LONGLONG    TimePassed, Timeout = LONGLONG_MAX;
909
        PLIST_ENTRY CurrentItem;
910
        BOOLEAN     bRemove;
911

912
        InterlockedExchange(&pContext->SelectInProgress, 1);
913

914
        InitializeListHead(&CompletionList);
915

916
        WdfWaitLockAcquire(pContext->SelectLock, NULL);
917

918
        TimePassed = VIOSockTimerPassed(&pContext->SelectTimer);
919

920
        for (CurrentItem = pContext->SelectList.Flink;
921
            CurrentItem != &pContext->SelectList;
922
            CurrentItem = CurrentItem->Flink)
923
        {
924
            PVIOSOCK_SELECT_PKT pPkt = CONTAINING_RECORD(CurrentItem, VIOSOCK_SELECT_PKT, ListEntry);
925
            WDFREQUEST Request = WdfObjectContextGetObject(pPkt);
926
            NTSTATUS status = WdfRequestUnmarkCancelable(Request);
927

928
            ASSERT(NT_SUCCESS(status) || status == STATUS_CANCELLED);
929

930
            bRemove = FALSE;
931

932
            if (status == STATUS_CANCELLED)
933
            {
934
                bRemove = TRUE;
935
                pPkt->Status = STATUS_CANCELLED;
936
            }
937
            else if (VIOSockSelectCheckPkt(pPkt))
938
            {
939
                bRemove = TRUE;
940
                pPkt->Status = STATUS_SUCCESS;
941
            }
942
            else if (pPkt->Timeout)
943
            {
944
                if (pPkt->Timeout <= TimePassed + VIOSOCK_TIMER_TOLERANCE)
945
                {
946
                    bRemove = TRUE;
947
                    pPkt->Status = STATUS_IO_TIMEOUT;
948
                }
949
                else
950
                {
951
                    pPkt->Timeout -= TimePassed;
952

953
                    if (pPkt->Timeout < Timeout)
954
                        Timeout = pPkt->Timeout;
955
                }
956
            }
957

958
            if (!bRemove)
959
            {
960
                status = WdfRequestMarkCancelableEx(Request, VIOSockSelectCancel);
961

962
                ASSERT(NT_SUCCESS(status) || status == STATUS_CANCELLED);
963

964
                if (status == STATUS_CANCELLED)
965
                {
966
                    bRemove = TRUE;
967
                    pPkt->Status = STATUS_CANCELLED;
968
                }
969
            }
970

971
            if (bRemove)
972
            {
973
                CurrentItem = pPkt->ListEntry.Blink;
974
                RemoveEntryList(&pPkt->ListEntry);
975
                InsertTailList(&CompletionList, &pPkt->ListEntry);
976
                if (pPkt->Timeout)
977
                    VIOSockTimerDeref(&pContext->SelectTimer, TRUE);
978
            }
979
        }
980

981
        if(Timeout!=LONGLONG_MAX)
982
            VIOSockTimerSet(&pContext->SelectTimer, Timeout);
983

984
        WdfWaitLockRelease(pContext->SelectLock);
985

986
        while (!IsListEmpty(&CompletionList))
987
        {
988
            PVIOSOCK_SELECT_PKT pPkt = CONTAINING_RECORD(RemoveHeadList(&CompletionList), VIOSOCK_SELECT_PKT, ListEntry);
989

990
            VIOSockSelectCleanupPkt(pPkt);
991
            WdfRequestCompleteWithInformation(WdfObjectContextGetObject(pPkt), pPkt->Status, pPkt->Status == STATUS_SUCCESS ? sizeof(VIRTIO_VSOCK_SELECT) : 0);
992
        }
993

994
    } while (InterlockedCompareExchange(&pContext->SelectInProgress, 0, 1) != 1);
995

996
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "<-- %s\n", __FUNCTION__);
997
}
998

999
_IRQL_requires_max_(DISPATCH_LEVEL)
1000
VOID
1001
VIOSockSelectRun(
1002
    IN PSOCKET_CONTEXT pSocket
1003
)
1004
{
1005
    BOOLEAN bRun = FALSE;
1006
    PDEVICE_CONTEXT pContext = GetDeviceContextFromSocket(pSocket);
1007

1008
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
1009

1010
    if (pSocket->SelectRefs[FDSET_READ])
1011
    {
1012
        bRun |= pSocket->Events & (FD_ACCEPT | FD_READ | FD_CLOSE);
1013
    }
1014

1015
    if (pSocket->SelectRefs[FDSET_WRITE])
1016
    {
1017
        bRun |= pSocket->Events & FD_WRITE ||
1018
            (pSocket->Events & FD_CONNECT) && NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]);
1019
    }
1020

1021
    if (pSocket->SelectRefs[FDSET_EXCPT])
1022
    {
1023
        bRun |= (pSocket->Events & FD_CONNECT) &&
1024
            !NT_SUCCESS(pSocket->EventsStatus[FD_CONNECT_BIT]);
1025
    }
1026

1027
    if (bRun && InterlockedIncrement(&pContext->SelectInProgress) == 1)
1028
    {
1029
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "Enqueue workitem\n");
1030
        WdfWorkItemEnqueue(pContext->SelectWorkitem);
1031
    }
1032

1033
}
1034

1035
static
1036
BOOLEAN
1037
VIOSockSelectCopyFds(
1038
    IN PDEVICE_CONTEXT          pContext,
1039
    IN BOOLEAN                  bIs32BitProcess,
1040
    IN PVIRTIO_VSOCK_SELECT     pSelect,
1041
    IN PVIOSOCK_SELECT_PKT      pPkt,
1042
    IN VIRTIO_VSOCK_FDSET_TYPE  iFdSet,
1043
    IN ULONG                    uStartIndex
1044
)
1045
{
1046
    ULONG                   i;
1047
    PVIOSOCK_SELECT_HANDLE  pHandleSet = &pPkt->Fds[uStartIndex];
1048

1049
    PAGED_CODE();
1050

1051
    pPkt->FdCount[iFdSet] = 0;
1052
    for (i = 0; i < pSelect->Fdss[iFdSet].fd_count; ++i)
1053
    {
1054
        ULONGLONG hSocket = pSelect->Fdss[iFdSet].fd_array[i];
1055
        if (hSocket)
1056
        {
1057
            WDFFILEOBJECT Socket = VIOSockGetSocketFromHandle(pContext, hSocket, bIs32BitProcess);
1058
            if (Socket != WDF_NO_HANDLE)
1059
            {
1060
                PSOCKET_CONTEXT pSocket = GetSocketContext(Socket);
1061

1062
                pHandleSet[i].hSocket = hSocket;
1063
                pHandleSet[i].Socket = Socket;
1064
                InterlockedIncrement(&pSocket->SelectRefs[iFdSet]); //reference socket
1065
            }
1066
            else
1067
                break;
1068
        }
1069
        else
1070
            break;
1071
    }
1072

1073
    pPkt->FdCount[iFdSet] = i;
1074

1075
    return i == pSelect->Fdss[iFdSet].fd_count;
1076
}
1077

1078
static
1079
NTSTATUS
1080
VIOSockSelect(
1081
    IN WDFREQUEST Request,
1082
    IN OUT size_t *pLength
1083
)
1084
{
1085
    PDEVICE_CONTEXT         pContext = GetDeviceContextFromRequest(Request);
1086
    PVIRTIO_VSOCK_SELECT    pSelect;
1087
    SIZE_T                  stSelectLen;
1088
    NTSTATUS                status;
1089
    BOOLEAN                 bIs32BitProcess = FALSE;
1090
    WDF_OBJECT_ATTRIBUTES   Attributes;
1091
    PVIOSOCK_SELECT_PKT     pPkt = NULL;
1092

1093
    PAGED_CODE();
1094

1095
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "--> %s\n", __FUNCTION__);
1096

1097
    *pLength = 0;
1098

1099
    status = WdfRequestRetrieveInputBuffer(Request, sizeof(*pSelect), &pSelect, &stSelectLen);
1100
    if (!NT_SUCCESS(status))
1101
    {
1102
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT, "WdfRequestRetrieveInputBuffer failed: 0x%x\n", status);
1103
        return status;
1104
    }
1105

1106
    // minimum length guaranteed by WdfRequestRetrieveInputBuffer above
1107
    _Analysis_assume_(stSelectLen >= sizeof(*pSelect));
1108

1109
    status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*pSelect), &pSelect, &stSelectLen);
1110
    if (!NT_SUCCESS(status))
1111
    {
1112
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT, "WdfRequestRetrieveOutputBuffer failed: 0x%x\n", status);
1113
        return status;
1114
    }
1115

1116
    // minimum length guaranteed by WdfRequestRetrieveInputBuffer above
1117
    _Analysis_assume_(stSelectLen >= sizeof(*pSelect));
1118

1119
    if (FD_SETSIZE < pSelect->Fdss[FDSET_READ].fd_count +
1120
        pSelect->Fdss[FDSET_WRITE].fd_count +
1121
        pSelect->Fdss[FDSET_EXCPT].fd_count)
1122
    {
1123
        return STATUS_INVALID_PARAMETER;
1124
    }
1125

1126
#ifdef _WIN64
1127
    bIs32BitProcess = WdfRequestIsFrom32BitProcess(Request);
1128
#endif //_WIN64
1129

1130
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
1131
        &Attributes,
1132
        VIOSOCK_SELECT_PKT
1133
    );
1134

1135
    status = WdfObjectAllocateContext(Request, &Attributes, &pPkt);
1136
    if (!NT_SUCCESS(status))
1137
    {
1138
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SELECT, "WdfObjectAllocateContext failed: 0x%x\n", status);
1139
        return status;
1140
    }
1141

1142
    pPkt->pSelect = pSelect;
1143

1144
    if (!VIOSockSelectCopyFds(pContext, bIs32BitProcess, pSelect, pPkt, FDSET_READ, 0) ||
1145
        !VIOSockSelectCopyFds(pContext, bIs32BitProcess, pSelect, pPkt, FDSET_WRITE, pPkt->FdCount[FDSET_READ]) ||
1146
        !VIOSockSelectCopyFds(pContext, bIs32BitProcess, pSelect, pPkt, FDSET_EXCPT,
1147
            pPkt->FdCount[FDSET_READ] + pPkt->FdCount[FDSET_WRITE]))
1148
    {
1149
        TraceEvents(TRACE_LEVEL_WARNING, DBG_SELECT, "VIOSockSelectCopyFds failed\n");
1150
        status = STATUS_INVALID_HANDLE;
1151
    }
1152

1153
    if (NT_SUCCESS(status))
1154
    {
1155
        WdfWaitLockAcquire(pContext->SelectLock, NULL);
1156

1157
        pPkt->Status = status = VIOSockSelectCheckPkt(pPkt) ? STATUS_SUCCESS : STATUS_PENDING;
1158

1159
        if (status == STATUS_PENDING)
1160
        {
1161
            status = WdfRequestMarkCancelableEx(Request, VIOSockSelectCancel);
1162

1163
            ASSERT(NT_SUCCESS(status) || status == STATUS_CANCELLED);
1164

1165
            if (NT_SUCCESS(status))
1166
            {
1167
                status = STATUS_PENDING;
1168

1169
                InsertTailList(&pContext->SelectList, &pPkt->ListEntry);
1170
                pPkt->Timeout = pSelect->Timeout;
1171

1172
                if (pPkt->Timeout)
1173
                    VIOSockTimerStart(&pContext->SelectTimer, pPkt->Timeout);
1174
            }
1175
        }
1176
        else
1177
            *pLength = sizeof(*pSelect);
1178

1179
        WdfWaitLockRelease(pContext->SelectLock);
1180
    }
1181

1182
    if (status != STATUS_PENDING)
1183
        VIOSockSelectCleanupPkt(pPkt);
1184

1185
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_SELECT, "<-- %s\n", __FUNCTION__);
1186

1187
    return status;
1188
}
1189

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.