kvm-guest-drivers-windows

Форк
0
1153 строки · 44.8 Кб
1
/*
2
 * This file contains implementation of minimal user-mode service
3
 *
4
 * Copyright (c) 2020 Red Hat, Inc.
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 "stdafx.h"
31

32
/*
33
    The protocol service replaces and extends the notification object.
34
    Unlike previous implementation when the VIOPROT was enabled only
35
    on especially defined set of adapters, now the VIOPROT is installed and
36
    enabled on all the ethernet adapters. The service is responsible for:
37
    - disable all other protocols/filters only when needed (when the adapter
38
      has the same MAC as virtio-net adapter)
39
    - enable all other protocols when the protocol is uninstalled
40
    - make standby netkvm adapter functional after several seconds if the VF
41
      is not present and reconnect via VF when the VF comes
42
    - enable all other protocols on VF when the netkvm is disabled
43
*/
44
#define SERVICE_EXEFILE  L"netkvmps.exe"
45
#define SERVICE_ORGFILE  L"netkvmp.exe"
46

47
class CNetCfg
48
{
49
public:
50
    CNetCfg()
51
    {
52
        hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_SERVER, IID_INetCfg, (LPVOID*)&m_NetCfg);
53
        if (!m_NetCfg) {
54
            return;
55
        }
56
        hr = m_NetCfg->QueryInterface(IID_INetCfgLock, (LPVOID*)&m_NetCfgLock);
57
        if (!m_NetCfgLock) {
58
            return;
59
        }
60
        m_Usable = m_NetCfgLock->AcquireWriteLock(5000, L"netkvmp service", NULL) == S_OK;
61
        if (m_Usable) {
62
            hr = m_NetCfg->Initialize(NULL);
63
            if (hr != S_OK) {
64
                m_NetCfgLock->ReleaseWriteLock();
65
                m_Usable = false;
66
            }
67
        }
68
    }
69
    ~CNetCfg()
70
    {
71
        if (!m_Usable) {
72
            return;
73
        }
74
        if (m_Modified)
75
        {
76
            Log("Applying binding changes");
77
            m_NetCfg->Apply();
78
        }
79
        m_NetCfg->Uninitialize();
80
        m_NetCfgLock->ReleaseWriteLock();
81
    }
82
    bool Usable() const { return m_Usable; }
83
    bool Find(LPCWSTR Name)
84
    {
85
        if (!Usable())
86
            return false;
87
        CComPtr<INetCfgComponent> component;
88
        hr = m_NetCfg->FindComponent(Name, &component);
89
        Log("%sound component %S(hr %X)", hr == S_OK ? "F" : "Not f", Name, hr);
90
        return hr == S_OK;
91
    }
92
    void EnableComponents(const CString& Name, tBindingState State)
93
    {
94
        if (!Usable())
95
            return;
96
        CComPtr<INetCfgClass> netClass;
97
        hr = m_NetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NET, IID_INetCfgClass, (LPVOID*)&netClass);
98
        if (hr != S_OK) {
99
            return;
100
        }
101
        CComPtr<IEnumNetCfgComponent> netEnum;
102
        hr = netClass->EnumComponents(&netEnum);
103
        if (hr != S_OK) {
104
            return;
105
        }
106
        do {
107
            CComPtr<INetCfgComponent> adapter;
108
            hr = netEnum->Next(1, &adapter, NULL);
109
            if (hr != S_OK) {
110
                break;
111
            }
112
            LPWSTR id = NULL;
113
            hr = adapter->GetDisplayName(&id);
114
            if (hr != S_OK) {
115
                continue;
116
            }
117
            bool found = !Name.CompareNoCase(id);
118
            CoTaskMemFree(id);
119
            if (found) {
120
                Log("found %S", Name.GetString());
121
                CComPtr<INetCfgComponentBindings> bindings;
122
                CComPtr<IEnumNetCfgBindingPath> paths;
123
                hr = adapter->QueryInterface(IID_INetCfgComponentBindings, (LPVOID*)&bindings);
124
                if (hr != S_OK) {
125
                    break;
126
                }
127
                hr = bindings->EnumBindingPaths(EBP_ABOVE, &paths);
128
                if (!paths) {
129
                    break;
130
                }
131
                while (true) {
132
                    CComPtr<INetCfgBindingPath> path;
133
                    hr = paths->Next(1, &path, NULL);
134
                    if (hr != S_OK) {
135
                        break;
136
                    }
137
                    ProcessAdapterPath(adapter, path, State);
138
                }
139
                break;
140
            }
141
        } while (true);
142
    }
143
private:
144
    CComPtr<INetCfg> m_NetCfg;
145
    CComPtr<INetCfgLock> m_NetCfgLock;
146
    bool m_Usable = false;
147
    bool m_Modified = false;
148
    HRESULT hr;
149
    void ProcessAdapterPath(INetCfgComponent* Adapter, INetCfgBindingPath* path, tBindingState State)
150
    {
151
        CString sVioProt = L"vioprot";
152
        CString sTcpip = L"ms_tcpip";
153
        bool enabled = path->IsEnabled() == S_OK;
154
        CComPtr<IEnumNetCfgBindingInterface> enumBindingIf;
155
        hr = path->EnumBindingInterfaces(&enumBindingIf);
156
        if (hr != S_OK) {
157
            return;
158
        }
159
        CComPtr<INetCfgBindingInterface> bindingIf;
160
        hr = enumBindingIf->Next(1, &bindingIf, NULL);
161
        if (hr != S_OK) {
162
            return;
163
        }
164
        LPWSTR upperId = NULL, lowerId = NULL;
165
        CComPtr<INetCfgComponent> upper, lower;
166
        bindingIf->GetUpperComponent(&upper);
167
        bindingIf->GetLowerComponent(&lower);
168
        if (upper) upper->GetId(&upperId);
169
        if (lower) lower->GetId(&lowerId);
170
        if (!upperId || !lowerId || lower != Adapter) {
171
            CoTaskMemFree(upperId);
172
            CoTaskMemFree(lowerId);
173
            return;
174
        }
175
        bool bIsVioProt = !sVioProt.CompareNoCase(upperId);
176
        bool bIsTcpip = !sTcpip.CompareNoCase(upperId);
177
        bool bShouldBeEnabled;
178
        // vioprot should be enabled always, all the rest - if 'Enable{OnlyVioProt}==false'
179
        switch (State)
180
        {
181
            case bsBindVioProt:
182
                bShouldBeEnabled = bIsVioProt;
183
                break;
184
            case bsBindOther:
185
                bShouldBeEnabled = !bIsVioProt;
186
                break;
187
            case bsBindNone:
188
                bShouldBeEnabled = false;
189
                break;
190
            case bsUnbindTcpip:
191
                bShouldBeEnabled = enabled && !bIsTcpip;
192
                break;
193
            case bsBindTcpip:
194
                bShouldBeEnabled = enabled || bIsTcpip;
195
                break;
196
            case bsBindNoChange:
197
                bShouldBeEnabled = enabled;
198
                break;
199
            case bsBindAll:
200
            default:
201
                bShouldBeEnabled = true;
202
                break;
203
        }
204
        Log("%sabled U:%S L:%S (should be %sabled)",
205
            enabled ? "en" : "dis", upperId, lowerId,
206
            bShouldBeEnabled ? "en" : "dis");
207
        if (bShouldBeEnabled != enabled)
208
        {
209
            hr = path->Enable(bShouldBeEnabled);
210
            if (hr != S_OK)
211
            {
212
                Log("Can't %sable hr=%X", bShouldBeEnabled ? "en" : "dis", hr);
213
            }
214
            else
215
            {
216
                m_Modified = true;
217
            }
218
        }
219
        CoTaskMemFree(upperId);
220
        CoTaskMemFree(lowerId);
221
    }
222
};
223

224
static bool IsVioProtInstalled()
225
{
226
    CNetCfg cfg;
227
    return cfg.Find(L"vioprot");
228
}
229

230
class CMACString
231
{
232
public:
233
    CMACString(const UCHAR* Address)
234
    {
235
        const char chars[] = "0123456789ABCDEF";
236
        for (int i = 0; i < 6; ++i)
237
        {
238
            UCHAR c = Address[i];
239
            m_Buffer[i * 3] = chars[c >> 4];
240
            m_Buffer[i * 3 + 1] = chars[c & 0x0f];
241
            m_Buffer[i * 3 + 2] = ':';
242
        }
243
        m_Buffer[sizeof(m_Buffer) - 1] = 0;
244
    }
245
    const char* Get() { return m_Buffer; }
246
private:
247
    char m_Buffer[6 * 3] = {};
248
};
249

250
class CInterfaceTable
251
{
252
public:
253
    CInterfaceTable()
254
    {
255
        // we can't use GetAdaptersTable as it does not allow to enumerate adapters
256
        // when both ms_tcpip and ms_tcpip6 are disabled
257
        // GetIfTable2 provides all the adapters including disabled ones
258
        GetIfTable2(&m_Table);
259
    }
260
private:
261
    template<typename TWorker> void TraverseTable(
262
        ULONG Index, UCHAR* Mac, bool Equal,
263
        tBindingState State, bool Existing, TWorker Worker)
264
    {
265
        CNetCfg cfg;
266
        for (ULONG i = 0; m_Table && i < m_Table->NumEntries; ++i)
267
        {
268
            auto& row = m_Table->Table[i];
269
            auto Compare = [&](const MIB_IF_ROW2& row) -> bool
270
            {
271
                bool res = row.Type == IF_TYPE_ETHERNET_CSMACD;
272
                res = res && !row.InterfaceAndOperStatusFlags.FilterInterface;
273
                if (Existing)
274
                {
275
                    res = res && row.OperStatus != IfOperStatusNotPresent;
276
                }
277
                if (Mac)
278
                {
279
                    res = res && !memcmp(Mac, row.PhysicalAddress, 6);
280
                }
281
                if (Equal)
282
                {
283
                    res = res && row.InterfaceIndex == Index;
284
                }
285
                else
286
                {
287
                    res = res && row.InterfaceIndex != Index;
288
                }
289
                return res;
290
            };
291
            if (Compare(row))
292
            {
293
                // Description - adapter name
294
                // Alias - connection name
295
                Log("IF %d (%S)(%S)", row.InterfaceIndex, row.Description, row.Alias);
296
                Worker(row);
297
                cfg.EnableComponents(row.Description, State);
298
            }
299
        }
300
    }
301
public:
302
    void CheckBinding(ULONG Index, UCHAR* Mac, bool Equal, tBindingState State, bool Existing)
303
    {
304
        TraverseTable(Index, Mac, Equal, State, Existing, [](const MIB_IF_ROW2&){});
305
    }
306
    // turn on-off TCPIP on existing adater, whose index is
307
    // equal or not equal to the known one
308
    void PulseTcpip(UCHAR *Mac, ULONG VfIndex, bool Equal)
309
    {
310
        CheckBinding(VfIndex, Mac, Equal, bsUnbindTcpip, true);
311
        CheckBinding(VfIndex, Mac, Equal, bsBindTcpip, true);
312
    }
313
    // simple version without MAC validation for all adapters (also disabled ones)
314
    void CheckBinding(ULONG Index, tBindingState State)
315
    {
316
        CheckBinding(Index, NULL, true, State, false);
317
    }
318
    void Dump()
319
    {
320
        TraverseTable(INFINITE, NULL, false, bsBindNoChange, false,
321
        [](const MIB_IF_ROW2& row)
322
        {
323
            CMACString sMac(row.PhysicalAddress);
324
            auto& fl = row.InterfaceAndOperStatusFlags;
325
            Log("[%s]  hw %d, paused %d, lp %d, %s",
326
                sMac.Get(),
327
                fl.HardwareInterface, fl.Paused, fl.LowPower,
328
                Name<IF_OPER_STATUS>(row.OperStatus));
329
        });
330
    }
331
    ~CInterfaceTable()
332
    {
333
        FreeMibTable(m_Table);
334
    }
335
private:
336
    PMIB_IF_TABLE2 m_Table = NULL;
337
};
338

339
class CDeviceNotificationOwner
340
{
341
public:
342
    CDeviceNotificationOwner() {}
343
    // return false only on CM_NOTIFY_ACTION_DEVICEQUERYREMOVE and only when needed
344
    virtual bool Notification(CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA data, DWORD dataSize) = 0;
345
};
346

347
class CDeviceNotification
348
{
349
public:
350
    CDeviceNotification(CDeviceNotificationOwner& owner) :
351
        m_Owner(owner)
352
    {
353
    }
354
    bool Register(CM_NOTIFY_FILTER* filter)
355
    {
356
        CONFIGRET cr = CM_Register_Notification(filter, this,
357
            [](HCMNOTIFICATION h, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize) -> DWORD
358
            {
359
                CDeviceNotification* obj = (CDeviceNotification*)Context;
360
                DWORD res = obj->Notification(Action, EventData, EventDataSize) ? ERROR_SUCCESS : ERROR_CANCELLED;
361
                if (res != ERROR_SUCCESS)
362
                {
363
                    Log("WARNING: returning %d from PnP notification", res);
364
                    UNREFERENCED_PARAMETER(h);
365
                }
366
                return res;
367
            },
368
            &m_Notification);
369
        if (!m_Notification)
370
        {
371
            Log("%s: failed to register, cr %d", __FUNCTION__, cr);
372
        }
373
        return m_Notification != NULL;
374
    }
375
    ~CDeviceNotification()
376
    {
377
        if (m_Notification)
378
        {
379
            CM_Unregister_Notification(m_Notification);
380
        }
381
        m_Notification = NULL;
382
    }
383
    bool Notification(CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA data, DWORD dataSize)
384
    {
385
        Log("%s: action %s", __FUNCTION__, Name<CM_NOTIFY_ACTION>(action));
386
        return m_Owner.Notification(action, data, dataSize);
387
    }
388
private:
389
    HCMNOTIFICATION m_Notification = NULL;
390
    CDeviceNotificationOwner& m_Owner;
391
};
392

393
class CNetworkDeviceNotification : public CDeviceNotification
394
{
395
public:
396
    CNetworkDeviceNotification(CDeviceNotificationOwner& owner) :
397
        CDeviceNotification(owner)
398
    {
399
        m_Filter.cbSize = sizeof(m_Filter);
400
        m_Filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
401
        m_Filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_NET;
402
        Register(&m_Filter);
403
    }
404
    CM_NOTIFY_FILTER m_Filter = {};
405
};
406

407
class CNetkvmDeviceFile
408
{
409
public:
410
    CNetkvmDeviceFile()
411
    {
412
        LPCWSTR devName = L"\\\\.\\" NETKVM_DEVICE_NAME;
413
        ULONG access = GENERIC_READ | GENERIC_WRITE, share = FILE_SHARE_READ | FILE_SHARE_WRITE;
414
        m_Handle = CreateFile(devName, access, share,
415
            NULL, OPEN_EXISTING, 0, NULL);
416
        if (m_Handle == INVALID_HANDLE_VALUE) {
417
            //Log("can't open %S(%d)\n", devName, GetLastError());
418
            m_Handle = NULL;
419
        }
420
    }
421
    ~CNetkvmDeviceFile()
422
    {
423
        if (m_Handle) {
424
            CloseHandle(m_Handle);
425
        }
426
    }
427
    bool ControlGet(ULONG Code, PVOID InBuf, ULONG InSize)
428
    {
429
        return Control(Code, NULL, 0, InBuf, InSize);
430
    }
431
    bool ControlSet(ULONG Code, PVOID OutBuf, ULONG OutSize)
432
    {
433
        return Control(Code, OutBuf, OutSize, NULL, 0);
434
    }
435
    bool Control(ULONG Code, PVOID InBuf, ULONG InSize, PVOID OutBuf, ULONG OutSize)
436
    {
437
        return DeviceIoControl(m_Handle, Code, InBuf, InSize, OutBuf, OutSize, &m_Returned, NULL);
438
    }
439
    bool Usable() const { return m_Handle; }
440
    ULONG Returned() const { return m_Returned; }
441
protected:
442
    HANDLE m_Handle;
443
    ULONG m_Returned = 0;
444
};
445

446
static void CheckBinding(ULONG Index, tBindingState State)
447
{
448
    CInterfaceTable t;
449
    t.CheckBinding(Index, State);
450
}
451

452
class CVirtioAdapter
453
{
454
public:
455
    CVirtioAdapter(UCHAR *Mac = NULL)
456
    {
457
        if (Mac)
458
        {
459
            RtlCopyMemory(m_MacAddress, Mac, sizeof(m_MacAddress));
460
        }
461
    }
462
    ULONG m_Count = 0;
463
    typedef enum _tAction { acNone, acOn, acOff } tAction;
464
    tAdapterState m_State = asUnknown;
465
    UCHAR m_MacAddress[6];
466
    ULONG m_VfIndex = INFINITE;
467
    bool Match(UCHAR* Mac)
468
    {
469
        return !memcmp(m_MacAddress, Mac, sizeof(m_MacAddress));
470
    }
471
    void SetState(tAdapterState State, const NETKVMD_ADAPTER& a)
472
    {
473
        tAction action = acNone;
474
        m_Count = 0;
475
        switch (State)
476
        {
477
            case asStandalone:
478
                // if SuppressLink or Started is set - this is our error
479
                // if VF present - probably we need to unbind it from everything
480
                break;
481
            case asAloneInactive:
482
                // virtio and standby are on, no vf, virtio link is off
483
                // if Suppressed is set, better to clear it
484
                if (a.SuppressLink) action = acOn;
485
                break;
486
            case asAloneActive:
487
                // virtio, standby, virtio link are on, no vf
488
                // if Suppressed is set, must clear it
489
                if (a.SuppressLink) action = acOn;
490
                break;
491
            case asBoundInactive:
492
                // virtio, standby, vf, but virtio link is off
493
                // wait for carrier
494
                // if suppressed is set, need to clear it
495
                if (a.SuppressLink) action = acOn;
496
                break;
497
            case asBoundInitial:
498
                // virtio, standby, vf, suppress, not started
499
                // for example after netkvm parameters change
500
                action = acOn;
501
                CheckBinding(a.VfIfIndex, bsBindVioProt);
502
                break;
503
            case asBoundActive:
504
                // working failover
505
                if (!a.SuppressLink && !a.Started)
506
                {
507
                    // VF comes when virtio becomes active after initial timeout
508
                    action = acOff;
509
                    m_Count = INFINITE;
510
                    CheckBinding(a.VfIfIndex, bsBindVioProt);
511
                }
512
                break;
513
            case asAbsent:
514
                // working VF without virtio
515
                // VF should be bound to all the protocols
516
                CheckBinding(a.VfIfIndex, bsBindAll);
517
                break;
518
            default:
519
                break;
520
        }
521
        m_State = State;
522
        SetLink(action);
523
    }
524
    void Update(const NETKVMD_ADAPTER& a)
525
    {
526
        ULONG index = 0;
527
        CMACString s(a.MacAddress);
528

529
        // here we convert seven booleans to 7-bit index
530
        // state is determined as m_TargetStates[index]
531
        if (a.Virtio) index |= 1;
532
        if (a.IsStandby) index |= 2;
533
        if (a.VirtioLink) index |= 4;
534
        if (a.SuppressLink) index |= 8;
535
        if (a.Started) index |= 16;
536
        if (a.HasVf)
537
        {
538
            index |= 32;
539
            m_VfIndex = a.VfIfIndex;
540
        }
541
        else if (m_VfIndex != INFINITE && IsVioProtInstalled())
542
        {
543
            CheckBinding(m_VfIndex, bsBindAll);
544
            m_VfIndex = INFINITE;
545
        }
546
        else if (m_VfIndex == INFINITE)
547
        {
548
            // no change
549
        }
550
        else
551
        {
552
            // protocol is uninstalled, this is the last round of update
553
            // the rest will be done by the tail of the thread
554
        }
555
        if (a.VfLink) index |= 64;
556
        tAdapterState State = m_TargetStates[index];
557
        if (State != m_State || m_Count == INFINITE)
558
        {
559
            Log("[%s] v%d, sb%d, l%d, su%d, st%d, vf%d, vfidx %d, vl%d",
560
                s.Get(), a.Virtio, a.IsStandby, a.VirtioLink, a.SuppressLink, a.Started, a.HasVf, a.VfIfIndex, a.VfLink);
561
            Log("[%s] %s => %s", s.Get(), Name<tAdapterState>(m_State), Name<tAdapterState>(State));
562
            SetState(State, a);
563
        }
564
        else
565
        {
566
            m_Count++;
567
        }
568
    }
569
    void Dump()
570
    {
571
        CMACString s(m_MacAddress);
572
        Log("[%s] %s vfIdx %d", s.Get(), Name<tAdapterState>(m_State), m_VfIndex);
573
    }
574
    void SetLink(tAction Action)
575
    {
576
        if (Action == acNone)
577
            return;
578
        NETKVMD_SET_LINK sl;
579
        RtlCopyMemory(sl.MacAddress, m_MacAddress, sizeof(m_MacAddress));
580
        sl.LinkOn = Action == acOn ? 1 : 0;
581
        CNetkvmDeviceFile d;
582
        d.ControlSet(IOCTL_NETKVMD_SET_LINK, &sl, sizeof(sl));
583
    }
584
    void PreRemove(tBindingState State)
585
    {
586
        CheckBinding(m_VfIndex, State);
587
    }
588
private:
589
    static const tAdapterState CVirtioAdapter::m_TargetStates[];
590
};
591

592
const tAdapterState CVirtioAdapter::m_TargetStates[128] =
593
{
594
    /* 0:  Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asUnknown,
595
    /* 1:  Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asStandalone,
596
    /* 2:  Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asUnknown,
597
    /* 3:  Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asAloneInactive,
598
    /* 4:  Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asUnknown,
599
    /* 5:  Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asStandalone,
600
    /* 6:  Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asUnknown,
601
    /* 7:  Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 0 */ asAloneActive,
602
    /* 8:  Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asUnknown,
603
    /* 9:  Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asStandalone,
604
    /* 10: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asUnknown,
605
    /* 11: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asAloneInactive,
606
    /* 12: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asUnknown,
607
    /* 13: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asStandalone,
608
    /* 14: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asUnknown,
609
    /* 15: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 0 */ asAloneActive,
610
    /* 16: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asUnknown,
611
    /* 17: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asStandalone,
612
    /* 18: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asUnknown,
613
    /* 19: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asAloneInactive,
614
    /* 20: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asUnknown,
615
    /* 21: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asStandalone,
616
    /* 22: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asUnknown,
617
    /* 23: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 0 */ asAloneActive,
618
    /* 24: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asUnknown,
619
    /* 25: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asStandalone,
620
    /* 26: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asUnknown,
621
    /* 27: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asAloneInactive,
622
    /* 28: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asUnknown,
623
    /* 29: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asStandalone,
624
    /* 30: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asUnknown,
625
    /* 31: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 0 */ asAloneActive,
626
    /* 32: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asAbsent,
627
    /* 33: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asStandalone,
628
    /* 34: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asUnknown,
629
    /* 35: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asAloneInactive,
630
    /* 36: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asUnknown,
631
    /* 37: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asStandalone,
632
    /* 38: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asUnknown,
633
    /* 39: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 0 */ asAloneInactive,
634
    /* 40: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asUnknown,
635
    /* 41: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asStandalone,
636
    /* 42: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asUnknown,
637
    /* 43: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asAloneInactive,
638
    /* 44: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asUnknown,
639
    /* 45: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asStandalone,
640
    /* 46: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asUnknown,
641
    /* 47: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 0 */ asAloneInactive,
642
    /* 48: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asUnknown,
643
    /* 49: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asStandalone,
644
    /* 50: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asUnknown,
645
    /* 51: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asAloneInactive,
646
    /* 52: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asUnknown,
647
    /* 53: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asStandalone,
648
    /* 54: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asUnknown,
649
    /* 55: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 0 */ asAloneInactive,
650
    /* 56: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asUnknown,
651
    /* 57: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asStandalone,
652
    /* 58: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asUnknown,
653
    /* 59: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asAloneInactive,
654
    /* 60: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asUnknown,
655
    /* 61: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asStandalone,
656
    /* 62: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asUnknown,
657
    /* 63: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 0 */ asBoundInactive,
658
    /* 64:  Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
659
    /* 65:  Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
660
    /* 66:  Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
661
    /* 67:  Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
662
    /* 68:  Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
663
    /* 69:  Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
664
    /* 70:  Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
665
    /* 71:  Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 0, VfLink 1 */ asUnknown,
666
    /* 72:  Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
667
    /* 73:  Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
668
    /* 74: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
669
    /* 75: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
670
    /* 76: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
671
    /* 77: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
672
    /* 78: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
673
    /* 79: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 0, VfLink 1 */ asUnknown,
674
    /* 80: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
675
    /* 81: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
676
    /* 82: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
677
    /* 83: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
678
    /* 84: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
679
    /* 85: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
680
    /* 86: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
681
    /* 87: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 0, VfLink 1 */ asUnknown,
682
    /* 88: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
683
    /* 89: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
684
    /* 90: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
685
    /* 91: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
686
    /* 92: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
687
    /* 93: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
688
    /* 94: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
689
    /* 95: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 0, VfLink 1 */ asUnknown,
690
    /* 96: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asAbsent,
691
    /* 97: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asStandalone,
692
    /* 98: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asUnknown,
693
    /* 99: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asBoundInactive,
694
    /* 100: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asUnknown,
695
    /* 101: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asStandalone,
696
    /* 102: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asUnknown,
697
    /* 103: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 0, HasVf 1, VfLink 1 */ asBoundActive,
698
    /* 104: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asUnknown,
699
    /* 105: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asStandalone,
700
    /* 106: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asUnknown,
701
    /* 107: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asBoundInactive,
702
    /* 108: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asUnknown,
703
    /* 109: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asStandalone,
704
    /* 110: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asUnknown,
705
    /* 111: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 0, HasVf 1, VfLink 1 */ asBoundInitial,
706
    /* 112: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asAbsent,
707
    /* 113: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asStandalone,
708
    /* 114: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asUnknown,
709
    /* 115: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asBoundInactive,
710
    /* 116: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asUnknown,
711
    /* 117: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asStandalone,
712
    /* 118: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asUnknown,
713
    /* 119: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 0, Started 1, HasVf 1, VfLink 1 */ asBoundActive,
714
    /* 120: Virtio 0, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asUnknown,
715
    /* 121: Virtio 1, IsStandby 0, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asStandalone,
716
    /* 122: Virtio 0, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asUnknown,
717
    /* 123: Virtio 1, IsStandby 1, VirtioLink 0, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asBoundInactive,
718
    /* 124: Virtio 0, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asUnknown,
719
    /* 125: Virtio 1, IsStandby 0, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asStandalone,
720
    /* 126: Virtio 0, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asUnknown,
721
    /* 127: Virtio 1, IsStandby 1, VirtioLink 1, SuppressLink 1, Started 1, HasVf 1, VfLink 1 */ asBoundActive,
722
};
723

724
class CVirtioAdaptersArray : public CAtlArray<CVirtioAdapter>
725
{
726
public:
727
    void RemoveAdapter(UINT Index, tBindingState State)
728
    {
729
        CVirtioAdapter& a = GetAt(Index);
730
        a.PreRemove(State);
731
        RemoveAt(Index);
732
    }
733
    void RemoveAllAdapters(tBindingState State)
734
    {
735
        for (UINT i = 0; i < GetCount(); ++i)
736
        {
737
            CVirtioAdapter& a = GetAt(i);
738
            a.PreRemove(State);
739
        }
740
        RemoveAll();
741
    }
742
};
743

744
class CFileFinder
745
{
746
public:
747
    CFileFinder(const CString& WildCard) : m_WildCard(WildCard) {};
748
    template<typename T> bool Process(T Functor)
749
    {
750
        HANDLE h = FindFirstFile(m_WildCard, &m_fd);
751
        if (h == INVALID_HANDLE_VALUE)
752
        {
753
            return false;
754
        }
755
        while (Functor(m_fd.cFileName) && FindNextFile(h, &m_fd)) {}
756
        FindClose(h);
757
        return true;
758
    }
759
private:
760
    WIN32_FIND_DATA m_fd = {};
761
    const CString& m_WildCard;
762
};
763

764
class CInfDirectory : public CString
765
{
766
public:
767
    CInfDirectory()
768
    {
769
        WCHAR* p = new WCHAR[MAX_PATH];
770
        if (p)
771
        {
772
            if (GetWindowsDirectory(p, MAX_PATH))
773
            {
774
                Append(p);
775
                Append(L"\\INF\\");
776
            }
777
            delete[] p;
778
        }
779
    }
780
};
781

782
class CSystemDirectory : public CString
783
{
784
public:
785
    CSystemDirectory()
786
    {
787
        WCHAR* p = new WCHAR[MAX_PATH];
788
        if (p)
789
        {
790
            if (GetSystemDirectory(p, MAX_PATH))
791
            {
792
                Append(p);
793
                Append(L"\\");
794
            }
795
            delete[] p;
796
        }
797
    }
798
};
799

800
// should always be called from the application
801
// instance, not from service one
802
static bool CopySelf()
803
{
804
    CSystemDirectory s;
805
    s += SERVICE_EXEFILE;
806
    bool done;
807
    int  retries = 0;
808
    do
809
    {
810
        done = CopyFile(CServiceImplementation::BinaryPath(), s, false);
811
        if (!done)
812
        {
813
            Log("%s: error %d", __FUNCTION__, GetLastError());
814
            retries++;
815
            Sleep(1000);
816
        }
817
        else
818
        {
819
            Log("%s: done", __FUNCTION__);
820
        }
821
    } while (!done && retries < 5);
822
    return done;
823
}
824

825
class CProtocolServiceImplementation :
826
    public CServiceImplementation,
827
    public CThreadOwner,
828
    public CDeviceNotificationOwner
829
{
830
public:
831
    CProtocolServiceImplementation() :
832
        CServiceImplementation(_T("netkvmp")),
833
        m_ThreadEvent(false)
834
        {}
835
    enum { ctlDump = 128 };
836
protected:
837
    virtual bool OnStart() override
838
    {
839
        StartThread();
840
        return true;
841
    }
842
    virtual DWORD ControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData)
843
    {
844
        DWORD res = NO_ERROR;
845
        switch (dwControl)
846
        {
847
            case ctlDump:
848
                Dump();
849
                return res;
850
            default:
851
                break;
852
        }
853
        res = __super::ControlHandler(dwControl, dwEventType, lpEventData);
854
        return res;
855
    }
856
    virtual bool OnStop() override
857
    {
858
        bool res = !IsThreadRunning();
859
        StopThread();
860
        m_ThreadEvent.Set();
861
        // if the thread is running, it will indicate stopped
862
        // state when the thread is terminated
863
        return res;
864
    }
865
    virtual void ThreadProc()
866
    {
867
        CNetworkDeviceNotification dn(*this);
868
        CoInitialize(NULL);
869

870
        do {
871
            SyncVirtioAdapters();
872
            if (ThreadState() != tsRunning)
873
                break;
874
            if (m_ThreadEvent.Wait(3000) == ERROR_SUCCESS)
875
            {
876
                // in most of cases this is network change
877
                // so let's check the file change
878
                CSystemDirectory sysdir;
879
                CString originalName = sysdir + SERVICE_ORGFILE;
880
                CString serviceName = BinaryPath();
881
                CString cmdLine;
882
                cmdLine.Format(L"fc /b %s %s > nul", originalName.GetString(), serviceName.GetString());
883
                int result = _wsystem(cmdLine);
884
                Log("Running %S = %d", cmdLine.GetString(), result);
885
                // both files exist and they are different
886
                if (result == 1)
887
                {
888
                    // run the original netkvmp.exe detached
889
                    CProcessRunner r(false, 0);
890
                    originalName += L" restartservice";
891
                    // in case of error - usually file not found
892
                    if (r.RunProcess(originalName) && r.ExitCode() != ERROR_FILE_NOT_FOUND)
893
                    {
894
                        break;
895
                    }
896
                }
897
            }
898
        } while (true);
899
        // Typical flow: the protocol is uninstalled
900
        if (!IsVioProtInstalled())
901
        {
902
            CInterfaceTable t;
903
            for (UINT i = 0; i < m_Adapters.GetCount(); ++i)
904
            {
905
                CVirtioAdapter& a = m_Adapters[i];
906
                if (a.m_VfIndex == INFINITE)
907
                    continue;
908
                switch (a.m_State)
909
                {
910
                    case asBoundInactive:
911
                    case asBoundActive:
912
                    case asAloneInactive:
913
                    case asAloneActive:
914
                        // make virtio-net inactive
915
                        a.SetLink(a.acOff);
916
                        // pulse the tcpip on virtio adapter, freeing the IP address
917
                        // and preventing DHCP error "Address ... being plumbed for adapter ... already exists"
918
                        t.PulseTcpip(a.m_MacAddress, a.m_VfIndex, false);
919
                        CheckBinding(a.m_VfIndex, bsBindAll);
920
                        break;
921
                    default:
922
                        break;
923
                }
924
            }
925
        }
926
        else
927
        {
928
            // The protocol will be restarted
929
        }
930
        CoUninitialize();
931
    }
932
    void ThreadTerminated(tThreadState previous)
933
    {
934
        __super::ThreadTerminated(previous);
935
        SetState(SERVICE_STOPPED);
936
    }
937

938
    void Dump()
939
    {
940
        CMutexProtect pr(m_AdaptersMutex);
941
        for (UINT i = 0; i < m_Adapters.GetCount(); ++i)
942
        {
943
            m_Adapters[i].Dump();
944
        }
945
        Log("Done (%d adapters)", m_Adapters.GetCount());
946
    }
947
private:
948
    CEvent m_ThreadEvent;
949
    CVirtioAdaptersArray m_Adapters;
950
    CMutex m_AdaptersMutex;
951
    bool Notification(CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA data, DWORD dataSize) override
952
    {
953
        UNREFERENCED_PARAMETER(action);
954
        UNREFERENCED_PARAMETER(data);
955
        UNREFERENCED_PARAMETER(dataSize);
956
        Log(" => Network change notification");
957
        m_ThreadEvent.Set();
958
        return true;
959
    }
960
private:
961
    NETKVMD_ADAPTER m_IoctlBuffer[256];
962
    void SyncVirtioAdapters()
963
    {
964
        CMutexProtect pr(m_AdaptersMutex);
965
        NETKVMD_ADAPTER* adapters = m_IoctlBuffer;
966
        ULONG n = 0;
967
        // device open-close scope
968
        {
969
            CNetkvmDeviceFile d;
970
            if (!d.Usable()) {
971
                m_Adapters.RemoveAllAdapters(bsBindAll);
972
            }
973
            if (!d.ControlGet(IOCTL_NETKVMD_QUERY_ADAPTERS, m_IoctlBuffer, sizeof(m_IoctlBuffer)))
974
            {
975
                m_Adapters.RemoveAllAdapters(bsBindAll);
976
            }
977
            else
978
            {
979
                n = d.Returned() / sizeof(NETKVMD_ADAPTER);
980
            }
981
        }
982
        // update existing adapters, add new ones
983
        for (ULONG i = 0; i < n; ++i)
984
        {
985
            bool found = false;
986
            for (ULONG j = 0; !found && j < m_Adapters.GetCount(); ++j)
987
            {
988
                found = m_Adapters[j].Match(adapters[i].MacAddress);
989
                if (!found) continue;
990
                m_Adapters[j].Update(adapters[i]);
991
            }
992
            if (found) continue;
993
            CVirtioAdapter a(adapters[i].MacAddress);
994
            a.Update(adapters[i]);
995
            m_Adapters.Add(a);
996
        }
997
        // remove all non-present adapters
998
        for (ULONG i = 0; i < m_Adapters.GetCount(); ++i)
999
        {
1000
            bool found = false;
1001
            for (ULONG j = 0; !found && j < n; ++j)
1002
            {
1003
                found = m_Adapters[i].Match(adapters[j].MacAddress);
1004
            }
1005
            if (found) continue;
1006
            m_Adapters.RemoveAdapter(i, bsBindAll);
1007
            i--;
1008
        }
1009
    }
1010
};
1011

1012
static CProtocolServiceImplementation DummyService;
1013

1014
static void UninstallProtocol()
1015
{
1016
    puts("Uninstalling VIOPROT");
1017
    system("netcfg -v -u VIOPROT");
1018
    CInfDirectory dir;
1019
    puts("Scan for protocol INF file...");
1020
    CFileFinder f(dir + L"oem*.inf");
1021
    f.Process([&](const TCHAR* Name)
1022
        {
1023
            CString completeName = dir + Name;
1024
            //printf("Checking %S...\n", Name);
1025
            CString s;
1026
            s.Format(L"type %s | findstr /i vioprot.cat", completeName.GetString());
1027
            int res = _wsystem(s);
1028
            if (!res)
1029
            {
1030
                printf("Uninstalling %S... ", Name);
1031
                res = SetupUninstallOEMInf(Name, SUOI_FORCEDELETE, NULL);
1032
                if (res)
1033
                {
1034
                    puts("Done");
1035
                }
1036
                else
1037
                {
1038
                    printf("Not done, error, error %d", GetLastError());
1039
                }
1040
            }
1041
            return true;
1042
        });
1043
}
1044

1045
static bool InstallProtocol()
1046
{
1047
    FILE* f = NULL;
1048
    fopen_s(&f, "vioprot.inf", "r");
1049
    if (f)
1050
    {
1051
        fclose(f);
1052
    }
1053
    if (!f)
1054
    {
1055
        puts("ERROR: File VIOPROT.INF is not in the current directory.");
1056
        return false;
1057
    }
1058
    if (!CopySelf())
1059
    {
1060
        puts("ERROR: Failed preparation for protocol installation.");
1061
        return false;
1062
    }
1063
    puts("Installing VIOPROT");
1064
    return !system("netcfg -v -l vioprot.inf -c p -i VIOPROT");
1065
}
1066

1067
static void Usage()
1068
{
1069
    puts("i(nstall)|u(ninstall)|q(uery)");
1070
}
1071

1072
int __cdecl main(int argc, char **argv)
1073
{
1074
    CStringA s;
1075
    if (argc > 1)
1076
    {
1077
       s = argv[1];
1078
    }
1079
    if (!s.CompareNoCase("restartservice"))
1080
    {
1081
        // will run in session 0, but it is not a service
1082
        CService service(DummyService.ServiceName());
1083
        ULONG state = SERVICE_RUNNING;
1084
        for (UINT i = 0; i < 5; ++i)
1085
        {
1086
            if (!service.Query(state) && state == SERVICE_STOPPED)
1087
            {
1088
                CopySelf();
1089
                service.Start();
1090
                break;
1091
            }
1092
            Sleep(1000);
1093
        }
1094
        return 0;
1095
    }
1096
    if (CServiceImplementation::CheckInMain())
1097
    {
1098
        return 0;
1099
    }
1100
    if (!s.IsEmpty())
1101
    {
1102
        CoInitialize(NULL);
1103
        if (!s.CompareNoCase("i") || !s.CompareNoCase("install"))
1104
        {
1105
            if (DummyService.Installed())
1106
            {
1107
                puts("Already installed");
1108
            }
1109
            else if (InstallProtocol())
1110
            {
1111
                puts("Protocol installed");
1112
            }
1113
        }
1114
        else if (!s.CompareNoCase("u") || !s.CompareNoCase("uninstall"))
1115
        {
1116
            if (DummyService.Installed())
1117
            {
1118
                UninstallProtocol();
1119
                DummyService.Uninstall();
1120
            }
1121
            else
1122
            {
1123
                puts("Service is not installed");
1124
                UninstallProtocol();
1125
            }
1126
        }
1127
        else if (!s.CompareNoCase("q") || !s.CompareNoCase("query"))
1128
        {
1129
            printf("Service %sinstalled\n", DummyService.Installed() ? "" : "not ");
1130
            printf("VIOPROT %sinstalled\n", IsVioProtInstalled() ? "" : "not ");
1131
        }
1132
        else if (!s.CompareNoCase("d") || !s.CompareNoCase("dump"))
1133
        {
1134
            DummyService.Control(CProtocolServiceImplementation::ctlDump);
1135
        }
1136
        else if (!s.CompareNoCase("e"))
1137
        {
1138
            puts("Dumping interface table to debug output");
1139
            CInterfaceTable t;
1140
            t.Dump();
1141
        }
1142
        else
1143
        {
1144
            Usage();
1145
        }
1146
        CoUninitialize();
1147
    }
1148
    else
1149
    {
1150
        Usage();
1151
    }
1152
    return 0;
1153
}
1154

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

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

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

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