kvm-guest-drivers-windows
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/*
33The protocol service replaces and extends the notification object.
34Unlike previous implementation when the VIOPROT was enabled only
35on especially defined set of adapters, now the VIOPROT is installed and
36enabled on all the ethernet adapters. The service is responsible for:
37- disable all other protocols/filters only when needed (when the adapter
38has 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
41is 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
47class CNetCfg
48{
49public:
50CNetCfg()
51{
52hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_SERVER, IID_INetCfg, (LPVOID*)&m_NetCfg);
53if (!m_NetCfg) {
54return;
55}
56hr = m_NetCfg->QueryInterface(IID_INetCfgLock, (LPVOID*)&m_NetCfgLock);
57if (!m_NetCfgLock) {
58return;
59}
60m_Usable = m_NetCfgLock->AcquireWriteLock(5000, L"netkvmp service", NULL) == S_OK;
61if (m_Usable) {
62hr = m_NetCfg->Initialize(NULL);
63if (hr != S_OK) {
64m_NetCfgLock->ReleaseWriteLock();
65m_Usable = false;
66}
67}
68}
69~CNetCfg()
70{
71if (!m_Usable) {
72return;
73}
74if (m_Modified)
75{
76Log("Applying binding changes");
77m_NetCfg->Apply();
78}
79m_NetCfg->Uninitialize();
80m_NetCfgLock->ReleaseWriteLock();
81}
82bool Usable() const { return m_Usable; }
83bool Find(LPCWSTR Name)
84{
85if (!Usable())
86return false;
87CComPtr<INetCfgComponent> component;
88hr = m_NetCfg->FindComponent(Name, &component);
89Log("%sound component %S(hr %X)", hr == S_OK ? "F" : "Not f", Name, hr);
90return hr == S_OK;
91}
92void EnableComponents(const CString& Name, tBindingState State)
93{
94if (!Usable())
95return;
96CComPtr<INetCfgClass> netClass;
97hr = m_NetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NET, IID_INetCfgClass, (LPVOID*)&netClass);
98if (hr != S_OK) {
99return;
100}
101CComPtr<IEnumNetCfgComponent> netEnum;
102hr = netClass->EnumComponents(&netEnum);
103if (hr != S_OK) {
104return;
105}
106do {
107CComPtr<INetCfgComponent> adapter;
108hr = netEnum->Next(1, &adapter, NULL);
109if (hr != S_OK) {
110break;
111}
112LPWSTR id = NULL;
113hr = adapter->GetDisplayName(&id);
114if (hr != S_OK) {
115continue;
116}
117bool found = !Name.CompareNoCase(id);
118CoTaskMemFree(id);
119if (found) {
120Log("found %S", Name.GetString());
121CComPtr<INetCfgComponentBindings> bindings;
122CComPtr<IEnumNetCfgBindingPath> paths;
123hr = adapter->QueryInterface(IID_INetCfgComponentBindings, (LPVOID*)&bindings);
124if (hr != S_OK) {
125break;
126}
127hr = bindings->EnumBindingPaths(EBP_ABOVE, &paths);
128if (!paths) {
129break;
130}
131while (true) {
132CComPtr<INetCfgBindingPath> path;
133hr = paths->Next(1, &path, NULL);
134if (hr != S_OK) {
135break;
136}
137ProcessAdapterPath(adapter, path, State);
138}
139break;
140}
141} while (true);
142}
143private:
144CComPtr<INetCfg> m_NetCfg;
145CComPtr<INetCfgLock> m_NetCfgLock;
146bool m_Usable = false;
147bool m_Modified = false;
148HRESULT hr;
149void ProcessAdapterPath(INetCfgComponent* Adapter, INetCfgBindingPath* path, tBindingState State)
150{
151CString sVioProt = L"vioprot";
152CString sTcpip = L"ms_tcpip";
153bool enabled = path->IsEnabled() == S_OK;
154CComPtr<IEnumNetCfgBindingInterface> enumBindingIf;
155hr = path->EnumBindingInterfaces(&enumBindingIf);
156if (hr != S_OK) {
157return;
158}
159CComPtr<INetCfgBindingInterface> bindingIf;
160hr = enumBindingIf->Next(1, &bindingIf, NULL);
161if (hr != S_OK) {
162return;
163}
164LPWSTR upperId = NULL, lowerId = NULL;
165CComPtr<INetCfgComponent> upper, lower;
166bindingIf->GetUpperComponent(&upper);
167bindingIf->GetLowerComponent(&lower);
168if (upper) upper->GetId(&upperId);
169if (lower) lower->GetId(&lowerId);
170if (!upperId || !lowerId || lower != Adapter) {
171CoTaskMemFree(upperId);
172CoTaskMemFree(lowerId);
173return;
174}
175bool bIsVioProt = !sVioProt.CompareNoCase(upperId);
176bool bIsTcpip = !sTcpip.CompareNoCase(upperId);
177bool bShouldBeEnabled;
178// vioprot should be enabled always, all the rest - if 'Enable{OnlyVioProt}==false'
179switch (State)
180{
181case bsBindVioProt:
182bShouldBeEnabled = bIsVioProt;
183break;
184case bsBindOther:
185bShouldBeEnabled = !bIsVioProt;
186break;
187case bsBindNone:
188bShouldBeEnabled = false;
189break;
190case bsUnbindTcpip:
191bShouldBeEnabled = enabled && !bIsTcpip;
192break;
193case bsBindTcpip:
194bShouldBeEnabled = enabled || bIsTcpip;
195break;
196case bsBindNoChange:
197bShouldBeEnabled = enabled;
198break;
199case bsBindAll:
200default:
201bShouldBeEnabled = true;
202break;
203}
204Log("%sabled U:%S L:%S (should be %sabled)",
205enabled ? "en" : "dis", upperId, lowerId,
206bShouldBeEnabled ? "en" : "dis");
207if (bShouldBeEnabled != enabled)
208{
209hr = path->Enable(bShouldBeEnabled);
210if (hr != S_OK)
211{
212Log("Can't %sable hr=%X", bShouldBeEnabled ? "en" : "dis", hr);
213}
214else
215{
216m_Modified = true;
217}
218}
219CoTaskMemFree(upperId);
220CoTaskMemFree(lowerId);
221}
222};
223
224static bool IsVioProtInstalled()
225{
226CNetCfg cfg;
227return cfg.Find(L"vioprot");
228}
229
230class CMACString
231{
232public:
233CMACString(const UCHAR* Address)
234{
235const char chars[] = "0123456789ABCDEF";
236for (int i = 0; i < 6; ++i)
237{
238UCHAR c = Address[i];
239m_Buffer[i * 3] = chars[c >> 4];
240m_Buffer[i * 3 + 1] = chars[c & 0x0f];
241m_Buffer[i * 3 + 2] = ':';
242}
243m_Buffer[sizeof(m_Buffer) - 1] = 0;
244}
245const char* Get() { return m_Buffer; }
246private:
247char m_Buffer[6 * 3] = {};
248};
249
250class CInterfaceTable
251{
252public:
253CInterfaceTable()
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
258GetIfTable2(&m_Table);
259}
260private:
261template<typename TWorker> void TraverseTable(
262ULONG Index, UCHAR* Mac, bool Equal,
263tBindingState State, bool Existing, TWorker Worker)
264{
265CNetCfg cfg;
266for (ULONG i = 0; m_Table && i < m_Table->NumEntries; ++i)
267{
268auto& row = m_Table->Table[i];
269auto Compare = [&](const MIB_IF_ROW2& row) -> bool
270{
271bool res = row.Type == IF_TYPE_ETHERNET_CSMACD;
272res = res && !row.InterfaceAndOperStatusFlags.FilterInterface;
273if (Existing)
274{
275res = res && row.OperStatus != IfOperStatusNotPresent;
276}
277if (Mac)
278{
279res = res && !memcmp(Mac, row.PhysicalAddress, 6);
280}
281if (Equal)
282{
283res = res && row.InterfaceIndex == Index;
284}
285else
286{
287res = res && row.InterfaceIndex != Index;
288}
289return res;
290};
291if (Compare(row))
292{
293// Description - adapter name
294// Alias - connection name
295Log("IF %d (%S)(%S)", row.InterfaceIndex, row.Description, row.Alias);
296Worker(row);
297cfg.EnableComponents(row.Description, State);
298}
299}
300}
301public:
302void CheckBinding(ULONG Index, UCHAR* Mac, bool Equal, tBindingState State, bool Existing)
303{
304TraverseTable(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
308void PulseTcpip(UCHAR *Mac, ULONG VfIndex, bool Equal)
309{
310CheckBinding(VfIndex, Mac, Equal, bsUnbindTcpip, true);
311CheckBinding(VfIndex, Mac, Equal, bsBindTcpip, true);
312}
313// simple version without MAC validation for all adapters (also disabled ones)
314void CheckBinding(ULONG Index, tBindingState State)
315{
316CheckBinding(Index, NULL, true, State, false);
317}
318void Dump()
319{
320TraverseTable(INFINITE, NULL, false, bsBindNoChange, false,
321[](const MIB_IF_ROW2& row)
322{
323CMACString sMac(row.PhysicalAddress);
324auto& fl = row.InterfaceAndOperStatusFlags;
325Log("[%s] hw %d, paused %d, lp %d, %s",
326sMac.Get(),
327fl.HardwareInterface, fl.Paused, fl.LowPower,
328Name<IF_OPER_STATUS>(row.OperStatus));
329});
330}
331~CInterfaceTable()
332{
333FreeMibTable(m_Table);
334}
335private:
336PMIB_IF_TABLE2 m_Table = NULL;
337};
338
339class CDeviceNotificationOwner
340{
341public:
342CDeviceNotificationOwner() {}
343// return false only on CM_NOTIFY_ACTION_DEVICEQUERYREMOVE and only when needed
344virtual bool Notification(CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA data, DWORD dataSize) = 0;
345};
346
347class CDeviceNotification
348{
349public:
350CDeviceNotification(CDeviceNotificationOwner& owner) :
351m_Owner(owner)
352{
353}
354bool Register(CM_NOTIFY_FILTER* filter)
355{
356CONFIGRET cr = CM_Register_Notification(filter, this,
357[](HCMNOTIFICATION h, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize) -> DWORD
358{
359CDeviceNotification* obj = (CDeviceNotification*)Context;
360DWORD res = obj->Notification(Action, EventData, EventDataSize) ? ERROR_SUCCESS : ERROR_CANCELLED;
361if (res != ERROR_SUCCESS)
362{
363Log("WARNING: returning %d from PnP notification", res);
364UNREFERENCED_PARAMETER(h);
365}
366return res;
367},
368&m_Notification);
369if (!m_Notification)
370{
371Log("%s: failed to register, cr %d", __FUNCTION__, cr);
372}
373return m_Notification != NULL;
374}
375~CDeviceNotification()
376{
377if (m_Notification)
378{
379CM_Unregister_Notification(m_Notification);
380}
381m_Notification = NULL;
382}
383bool Notification(CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA data, DWORD dataSize)
384{
385Log("%s: action %s", __FUNCTION__, Name<CM_NOTIFY_ACTION>(action));
386return m_Owner.Notification(action, data, dataSize);
387}
388private:
389HCMNOTIFICATION m_Notification = NULL;
390CDeviceNotificationOwner& m_Owner;
391};
392
393class CNetworkDeviceNotification : public CDeviceNotification
394{
395public:
396CNetworkDeviceNotification(CDeviceNotificationOwner& owner) :
397CDeviceNotification(owner)
398{
399m_Filter.cbSize = sizeof(m_Filter);
400m_Filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
401m_Filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_NET;
402Register(&m_Filter);
403}
404CM_NOTIFY_FILTER m_Filter = {};
405};
406
407class CNetkvmDeviceFile
408{
409public:
410CNetkvmDeviceFile()
411{
412LPCWSTR devName = L"\\\\.\\" NETKVM_DEVICE_NAME;
413ULONG access = GENERIC_READ | GENERIC_WRITE, share = FILE_SHARE_READ | FILE_SHARE_WRITE;
414m_Handle = CreateFile(devName, access, share,
415NULL, OPEN_EXISTING, 0, NULL);
416if (m_Handle == INVALID_HANDLE_VALUE) {
417//Log("can't open %S(%d)\n", devName, GetLastError());
418m_Handle = NULL;
419}
420}
421~CNetkvmDeviceFile()
422{
423if (m_Handle) {
424CloseHandle(m_Handle);
425}
426}
427bool ControlGet(ULONG Code, PVOID InBuf, ULONG InSize)
428{
429return Control(Code, NULL, 0, InBuf, InSize);
430}
431bool ControlSet(ULONG Code, PVOID OutBuf, ULONG OutSize)
432{
433return Control(Code, OutBuf, OutSize, NULL, 0);
434}
435bool Control(ULONG Code, PVOID InBuf, ULONG InSize, PVOID OutBuf, ULONG OutSize)
436{
437return DeviceIoControl(m_Handle, Code, InBuf, InSize, OutBuf, OutSize, &m_Returned, NULL);
438}
439bool Usable() const { return m_Handle; }
440ULONG Returned() const { return m_Returned; }
441protected:
442HANDLE m_Handle;
443ULONG m_Returned = 0;
444};
445
446static void CheckBinding(ULONG Index, tBindingState State)
447{
448CInterfaceTable t;
449t.CheckBinding(Index, State);
450}
451
452class CVirtioAdapter
453{
454public:
455CVirtioAdapter(UCHAR *Mac = NULL)
456{
457if (Mac)
458{
459RtlCopyMemory(m_MacAddress, Mac, sizeof(m_MacAddress));
460}
461}
462ULONG m_Count = 0;
463typedef enum _tAction { acNone, acOn, acOff } tAction;
464tAdapterState m_State = asUnknown;
465UCHAR m_MacAddress[6];
466ULONG m_VfIndex = INFINITE;
467bool Match(UCHAR* Mac)
468{
469return !memcmp(m_MacAddress, Mac, sizeof(m_MacAddress));
470}
471void SetState(tAdapterState State, const NETKVMD_ADAPTER& a)
472{
473tAction action = acNone;
474m_Count = 0;
475switch (State)
476{
477case asStandalone:
478// if SuppressLink or Started is set - this is our error
479// if VF present - probably we need to unbind it from everything
480break;
481case asAloneInactive:
482// virtio and standby are on, no vf, virtio link is off
483// if Suppressed is set, better to clear it
484if (a.SuppressLink) action = acOn;
485break;
486case asAloneActive:
487// virtio, standby, virtio link are on, no vf
488// if Suppressed is set, must clear it
489if (a.SuppressLink) action = acOn;
490break;
491case asBoundInactive:
492// virtio, standby, vf, but virtio link is off
493// wait for carrier
494// if suppressed is set, need to clear it
495if (a.SuppressLink) action = acOn;
496break;
497case asBoundInitial:
498// virtio, standby, vf, suppress, not started
499// for example after netkvm parameters change
500action = acOn;
501CheckBinding(a.VfIfIndex, bsBindVioProt);
502break;
503case asBoundActive:
504// working failover
505if (!a.SuppressLink && !a.Started)
506{
507// VF comes when virtio becomes active after initial timeout
508action = acOff;
509m_Count = INFINITE;
510CheckBinding(a.VfIfIndex, bsBindVioProt);
511}
512break;
513case asAbsent:
514// working VF without virtio
515// VF should be bound to all the protocols
516CheckBinding(a.VfIfIndex, bsBindAll);
517break;
518default:
519break;
520}
521m_State = State;
522SetLink(action);
523}
524void Update(const NETKVMD_ADAPTER& a)
525{
526ULONG index = 0;
527CMACString s(a.MacAddress);
528
529// here we convert seven booleans to 7-bit index
530// state is determined as m_TargetStates[index]
531if (a.Virtio) index |= 1;
532if (a.IsStandby) index |= 2;
533if (a.VirtioLink) index |= 4;
534if (a.SuppressLink) index |= 8;
535if (a.Started) index |= 16;
536if (a.HasVf)
537{
538index |= 32;
539m_VfIndex = a.VfIfIndex;
540}
541else if (m_VfIndex != INFINITE && IsVioProtInstalled())
542{
543CheckBinding(m_VfIndex, bsBindAll);
544m_VfIndex = INFINITE;
545}
546else if (m_VfIndex == INFINITE)
547{
548// no change
549}
550else
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}
555if (a.VfLink) index |= 64;
556tAdapterState State = m_TargetStates[index];
557if (State != m_State || m_Count == INFINITE)
558{
559Log("[%s] v%d, sb%d, l%d, su%d, st%d, vf%d, vfidx %d, vl%d",
560s.Get(), a.Virtio, a.IsStandby, a.VirtioLink, a.SuppressLink, a.Started, a.HasVf, a.VfIfIndex, a.VfLink);
561Log("[%s] %s => %s", s.Get(), Name<tAdapterState>(m_State), Name<tAdapterState>(State));
562SetState(State, a);
563}
564else
565{
566m_Count++;
567}
568}
569void Dump()
570{
571CMACString s(m_MacAddress);
572Log("[%s] %s vfIdx %d", s.Get(), Name<tAdapterState>(m_State), m_VfIndex);
573}
574void SetLink(tAction Action)
575{
576if (Action == acNone)
577return;
578NETKVMD_SET_LINK sl;
579RtlCopyMemory(sl.MacAddress, m_MacAddress, sizeof(m_MacAddress));
580sl.LinkOn = Action == acOn ? 1 : 0;
581CNetkvmDeviceFile d;
582d.ControlSet(IOCTL_NETKVMD_SET_LINK, &sl, sizeof(sl));
583}
584void PreRemove(tBindingState State)
585{
586CheckBinding(m_VfIndex, State);
587}
588private:
589static const tAdapterState CVirtioAdapter::m_TargetStates[];
590};
591
592const 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
724class CVirtioAdaptersArray : public CAtlArray<CVirtioAdapter>
725{
726public:
727void RemoveAdapter(UINT Index, tBindingState State)
728{
729CVirtioAdapter& a = GetAt(Index);
730a.PreRemove(State);
731RemoveAt(Index);
732}
733void RemoveAllAdapters(tBindingState State)
734{
735for (UINT i = 0; i < GetCount(); ++i)
736{
737CVirtioAdapter& a = GetAt(i);
738a.PreRemove(State);
739}
740RemoveAll();
741}
742};
743
744class CFileFinder
745{
746public:
747CFileFinder(const CString& WildCard) : m_WildCard(WildCard) {};
748template<typename T> bool Process(T Functor)
749{
750HANDLE h = FindFirstFile(m_WildCard, &m_fd);
751if (h == INVALID_HANDLE_VALUE)
752{
753return false;
754}
755while (Functor(m_fd.cFileName) && FindNextFile(h, &m_fd)) {}
756FindClose(h);
757return true;
758}
759private:
760WIN32_FIND_DATA m_fd = {};
761const CString& m_WildCard;
762};
763
764class CInfDirectory : public CString
765{
766public:
767CInfDirectory()
768{
769WCHAR* p = new WCHAR[MAX_PATH];
770if (p)
771{
772if (GetWindowsDirectory(p, MAX_PATH))
773{
774Append(p);
775Append(L"\\INF\\");
776}
777delete[] p;
778}
779}
780};
781
782class CSystemDirectory : public CString
783{
784public:
785CSystemDirectory()
786{
787WCHAR* p = new WCHAR[MAX_PATH];
788if (p)
789{
790if (GetSystemDirectory(p, MAX_PATH))
791{
792Append(p);
793Append(L"\\");
794}
795delete[] p;
796}
797}
798};
799
800// should always be called from the application
801// instance, not from service one
802static bool CopySelf()
803{
804CSystemDirectory s;
805s += SERVICE_EXEFILE;
806bool done;
807int retries = 0;
808do
809{
810done = CopyFile(CServiceImplementation::BinaryPath(), s, false);
811if (!done)
812{
813Log("%s: error %d", __FUNCTION__, GetLastError());
814retries++;
815Sleep(1000);
816}
817else
818{
819Log("%s: done", __FUNCTION__);
820}
821} while (!done && retries < 5);
822return done;
823}
824
825class CProtocolServiceImplementation :
826public CServiceImplementation,
827public CThreadOwner,
828public CDeviceNotificationOwner
829{
830public:
831CProtocolServiceImplementation() :
832CServiceImplementation(_T("netkvmp")),
833m_ThreadEvent(false)
834{}
835enum { ctlDump = 128 };
836protected:
837virtual bool OnStart() override
838{
839StartThread();
840return true;
841}
842virtual DWORD ControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData)
843{
844DWORD res = NO_ERROR;
845switch (dwControl)
846{
847case ctlDump:
848Dump();
849return res;
850default:
851break;
852}
853res = __super::ControlHandler(dwControl, dwEventType, lpEventData);
854return res;
855}
856virtual bool OnStop() override
857{
858bool res = !IsThreadRunning();
859StopThread();
860m_ThreadEvent.Set();
861// if the thread is running, it will indicate stopped
862// state when the thread is terminated
863return res;
864}
865virtual void ThreadProc()
866{
867CNetworkDeviceNotification dn(*this);
868CoInitialize(NULL);
869
870do {
871SyncVirtioAdapters();
872if (ThreadState() != tsRunning)
873break;
874if (m_ThreadEvent.Wait(3000) == ERROR_SUCCESS)
875{
876// in most of cases this is network change
877// so let's check the file change
878CSystemDirectory sysdir;
879CString originalName = sysdir + SERVICE_ORGFILE;
880CString serviceName = BinaryPath();
881CString cmdLine;
882cmdLine.Format(L"fc /b %s %s > nul", originalName.GetString(), serviceName.GetString());
883int result = _wsystem(cmdLine);
884Log("Running %S = %d", cmdLine.GetString(), result);
885// both files exist and they are different
886if (result == 1)
887{
888// run the original netkvmp.exe detached
889CProcessRunner r(false, 0);
890originalName += L" restartservice";
891// in case of error - usually file not found
892if (r.RunProcess(originalName) && r.ExitCode() != ERROR_FILE_NOT_FOUND)
893{
894break;
895}
896}
897}
898} while (true);
899// Typical flow: the protocol is uninstalled
900if (!IsVioProtInstalled())
901{
902CInterfaceTable t;
903for (UINT i = 0; i < m_Adapters.GetCount(); ++i)
904{
905CVirtioAdapter& a = m_Adapters[i];
906if (a.m_VfIndex == INFINITE)
907continue;
908switch (a.m_State)
909{
910case asBoundInactive:
911case asBoundActive:
912case asAloneInactive:
913case asAloneActive:
914// make virtio-net inactive
915a.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"
918t.PulseTcpip(a.m_MacAddress, a.m_VfIndex, false);
919CheckBinding(a.m_VfIndex, bsBindAll);
920break;
921default:
922break;
923}
924}
925}
926else
927{
928// The protocol will be restarted
929}
930CoUninitialize();
931}
932void ThreadTerminated(tThreadState previous)
933{
934__super::ThreadTerminated(previous);
935SetState(SERVICE_STOPPED);
936}
937
938void Dump()
939{
940CMutexProtect pr(m_AdaptersMutex);
941for (UINT i = 0; i < m_Adapters.GetCount(); ++i)
942{
943m_Adapters[i].Dump();
944}
945Log("Done (%d adapters)", m_Adapters.GetCount());
946}
947private:
948CEvent m_ThreadEvent;
949CVirtioAdaptersArray m_Adapters;
950CMutex m_AdaptersMutex;
951bool Notification(CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA data, DWORD dataSize) override
952{
953UNREFERENCED_PARAMETER(action);
954UNREFERENCED_PARAMETER(data);
955UNREFERENCED_PARAMETER(dataSize);
956Log(" => Network change notification");
957m_ThreadEvent.Set();
958return true;
959}
960private:
961NETKVMD_ADAPTER m_IoctlBuffer[256];
962void SyncVirtioAdapters()
963{
964CMutexProtect pr(m_AdaptersMutex);
965NETKVMD_ADAPTER* adapters = m_IoctlBuffer;
966ULONG n = 0;
967// device open-close scope
968{
969CNetkvmDeviceFile d;
970if (!d.Usable()) {
971m_Adapters.RemoveAllAdapters(bsBindAll);
972}
973if (!d.ControlGet(IOCTL_NETKVMD_QUERY_ADAPTERS, m_IoctlBuffer, sizeof(m_IoctlBuffer)))
974{
975m_Adapters.RemoveAllAdapters(bsBindAll);
976}
977else
978{
979n = d.Returned() / sizeof(NETKVMD_ADAPTER);
980}
981}
982// update existing adapters, add new ones
983for (ULONG i = 0; i < n; ++i)
984{
985bool found = false;
986for (ULONG j = 0; !found && j < m_Adapters.GetCount(); ++j)
987{
988found = m_Adapters[j].Match(adapters[i].MacAddress);
989if (!found) continue;
990m_Adapters[j].Update(adapters[i]);
991}
992if (found) continue;
993CVirtioAdapter a(adapters[i].MacAddress);
994a.Update(adapters[i]);
995m_Adapters.Add(a);
996}
997// remove all non-present adapters
998for (ULONG i = 0; i < m_Adapters.GetCount(); ++i)
999{
1000bool found = false;
1001for (ULONG j = 0; !found && j < n; ++j)
1002{
1003found = m_Adapters[i].Match(adapters[j].MacAddress);
1004}
1005if (found) continue;
1006m_Adapters.RemoveAdapter(i, bsBindAll);
1007i--;
1008}
1009}
1010};
1011
1012static CProtocolServiceImplementation DummyService;
1013
1014static void UninstallProtocol()
1015{
1016puts("Uninstalling VIOPROT");
1017system("netcfg -v -u VIOPROT");
1018CInfDirectory dir;
1019puts("Scan for protocol INF file...");
1020CFileFinder f(dir + L"oem*.inf");
1021f.Process([&](const TCHAR* Name)
1022{
1023CString completeName = dir + Name;
1024//printf("Checking %S...\n", Name);
1025CString s;
1026s.Format(L"type %s | findstr /i vioprot.cat", completeName.GetString());
1027int res = _wsystem(s);
1028if (!res)
1029{
1030printf("Uninstalling %S... ", Name);
1031res = SetupUninstallOEMInf(Name, SUOI_FORCEDELETE, NULL);
1032if (res)
1033{
1034puts("Done");
1035}
1036else
1037{
1038printf("Not done, error, error %d", GetLastError());
1039}
1040}
1041return true;
1042});
1043}
1044
1045static bool InstallProtocol()
1046{
1047FILE* f = NULL;
1048fopen_s(&f, "vioprot.inf", "r");
1049if (f)
1050{
1051fclose(f);
1052}
1053if (!f)
1054{
1055puts("ERROR: File VIOPROT.INF is not in the current directory.");
1056return false;
1057}
1058if (!CopySelf())
1059{
1060puts("ERROR: Failed preparation for protocol installation.");
1061return false;
1062}
1063puts("Installing VIOPROT");
1064return !system("netcfg -v -l vioprot.inf -c p -i VIOPROT");
1065}
1066
1067static void Usage()
1068{
1069puts("i(nstall)|u(ninstall)|q(uery)");
1070}
1071
1072int __cdecl main(int argc, char **argv)
1073{
1074CStringA s;
1075if (argc > 1)
1076{
1077s = argv[1];
1078}
1079if (!s.CompareNoCase("restartservice"))
1080{
1081// will run in session 0, but it is not a service
1082CService service(DummyService.ServiceName());
1083ULONG state = SERVICE_RUNNING;
1084for (UINT i = 0; i < 5; ++i)
1085{
1086if (!service.Query(state) && state == SERVICE_STOPPED)
1087{
1088CopySelf();
1089service.Start();
1090break;
1091}
1092Sleep(1000);
1093}
1094return 0;
1095}
1096if (CServiceImplementation::CheckInMain())
1097{
1098return 0;
1099}
1100if (!s.IsEmpty())
1101{
1102CoInitialize(NULL);
1103if (!s.CompareNoCase("i") || !s.CompareNoCase("install"))
1104{
1105if (DummyService.Installed())
1106{
1107puts("Already installed");
1108}
1109else if (InstallProtocol())
1110{
1111puts("Protocol installed");
1112}
1113}
1114else if (!s.CompareNoCase("u") || !s.CompareNoCase("uninstall"))
1115{
1116if (DummyService.Installed())
1117{
1118UninstallProtocol();
1119DummyService.Uninstall();
1120}
1121else
1122{
1123puts("Service is not installed");
1124UninstallProtocol();
1125}
1126}
1127else if (!s.CompareNoCase("q") || !s.CompareNoCase("query"))
1128{
1129printf("Service %sinstalled\n", DummyService.Installed() ? "" : "not ");
1130printf("VIOPROT %sinstalled\n", IsVioProtInstalled() ? "" : "not ");
1131}
1132else if (!s.CompareNoCase("d") || !s.CompareNoCase("dump"))
1133{
1134DummyService.Control(CProtocolServiceImplementation::ctlDump);
1135}
1136else if (!s.CompareNoCase("e"))
1137{
1138puts("Dumping interface table to debug output");
1139CInterfaceTable t;
1140t.Dump();
1141}
1142else
1143{
1144Usage();
1145}
1146CoUninitialize();
1147}
1148else
1149{
1150Usage();
1151}
1152return 0;
1153}
1154