📄 miniport.c
字号:
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
//
// (c) Microsoft Corporation. All rights reserved.
//
// This file is part of the Microsoft Virtual Ring Routing distribution.
// You should have received a copy of the Microsoft Research Shared Source
// license agreement (MSR-SSLA) for this software; see the file "license.txt".
// If not, please see http://research.microsoft.com/vrr/license.htm,
// or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
//
// This file is derived from the Microsoft Research Mesh Connectivity Layer,
// available under the MSR-SSLA license, and downloadable from
// http://research.microsoft.com/mesh/.
//
#include "headers.h"
static void
MiniportRescheduleTimeoutHelper(MiniportAdapter *VA, Time Now, Time Timeout);
uint NextVirtualAdapterIndex;
NDIS_HANDLE MiniportHandle;
NDIS_HANDLE OurDeviceHandle;
struct MiniportAdapters MiniportAdapters;
#define MINIPORT_MAX_MULTICAST_ADDRESS 16
//#define MINIPORT_MAX_FRAME_SIZE 1280 // Original LQSR. See also "MINIPORT_MAX_FRAME_SIZE (1280) bytes"
//
// VRR does not piggyback control messages on data packets.
// This is reasonable because there is less control traffic.
// Aside from the VRR header and advertise the rest as MTU.
//
#define MINIPORT_HEADER_SIZE sizeof(EtherHeader)
#define MINIPORT_MAX_FRAME_SIZE (PROTOCOL_MIN_FRAME_SIZE - MINIPORT_HEADER_SIZE - sizeof(VRRHeader))
#define MINIPORT_MAX_LOOKAHEAD 0xffff
#define MAX_RECV_QUEUE_SIZE 16
#define MINIPORT_TIMEOUT 100 // Milliseconds.
#define DEFAULT_METRIC WCETT
static void
MiniportTimeout(PKDPC Dpc, void *Context, void *Unused1, void *Unused2);
//* FindVirtualAdapterFromIndex
//
// Given an index, returns the virtual adapter.
//
MiniportAdapter *
FindVirtualAdapterFromIndex(uint Index)
{
MiniportAdapter *VA;
KIRQL OldIrql;
KeAcquireSpinLock(&MiniportAdapters.Lock, &OldIrql);
for (VA = MiniportAdapters.VirtualAdapters;
VA != NULL;
VA = VA->Next) {
//
// Is this the desired virtual adapter?
//
if (VA->Index == Index)
break;
}
KeReleaseSpinLock(&MiniportAdapters.Lock, OldIrql);
return VA;
}
//* FindVirtualAdapterFromGuid
//
// Given a guid, returns the virtual adapter.
//
MiniportAdapter *
FindVirtualAdapterFromGuid(const GUID *Guid)
{
MiniportAdapter *VA;
KIRQL OldIrql;
KeAcquireSpinLock(&MiniportAdapters.Lock, &OldIrql);
for (VA = MiniportAdapters.VirtualAdapters;
VA != NULL;
VA = VA->Next) {
//
// Is this the desired virtual adapter?
//
if (RtlEqualMemory(Guid, &VA->Guid, sizeof(GUID)))
break;
}
KeReleaseSpinLock(&MiniportAdapters.Lock, OldIrql);
return VA;
}
//* MiniportReadOrCreateAdapterAddress
//
// Reads a virtual address from the registry,
// or if the address is not present, creates a new address
// and persists it in the registry.
//
NDIS_STATUS
MiniportReadOrCreateAdapterAddress(
IN HANDLE KeyHandle,
OUT VirtualAddress Address)
{
NTSTATUS Status;
Status = GetRegNetworkAddress(KeyHandle, L"NetworkAddress", Address);
if (! NT_SUCCESS(Status)) {
//
// Create a pseudo-random address.
//
GetRandom(Address, VIRTUAL_ADDR_LENGTH);
//
// Clear the individual/group bit and
// the local/universal bit:
// We want a universal individual address.
//
IEEE_802_ADDR_CLEAR_GROUP(Address);
IEEE_802_ADDR_CLEAR_LOCAL(Address);
//
// Write the new address to the registry.
//
Status = SetRegNetworkAddress(KeyHandle, L"NetworkAddress", Address);
if (! NT_SUCCESS(Status)) {
KdPrint(("VRR!SetRegNetworkAddress -> %x\n", Status));
return NDIS_STATUS_FAILURE;
}
}
return NDIS_STATUS_SUCCESS;
}
//* MiniportIsInfinite
//
// Returns TRUE if the link metric indicates that the link
// is effectively broken.
//
boolint
MiniportIsInfinite(uint Metric)
{
return Metric == (uint)-1;
}
//* MiniportConvMetric
//
// Converts a link metric to a path metric.
//
uint
MiniportConvMetric(uint LinkMetric)
{
return LinkMetric;
}
//* MiniportPathMetric
//
// Calculates the path metric of an array of links,
// by summing the metrics of the links.
//
// Called with the link cache locked.
//
uint
MiniportPathMetric(
MiniportAdapter *VA,
Link **Hops,
uint NumHops)
{
uint Metric;
uint New;
uint i;
Metric = 0;
for (i = 0; i < NumHops; i++) {
//
// Check for a broken link.
//
if ((*VA->IsInfinite)(Hops[i]->Metric)) {
Metric = (uint)-1;
break;
}
//
// Check for overflow.
//
New = Metric + (*VA->ConvMetric)(Hops[i]->Metric);
if (New < Metric) {
Metric = (uint)-1;
break;
}
Metric = New;
}
return Metric;
}
//* MiniportInitLinkMetric
//
// Initialize metric information for a new link.
//
void
MiniportInitLinkMetric(
MiniportAdapter *VA,
int SNode,
Link *Link,
Time Now)
{
UNREFERENCED_PARAMETER(VA);
UNREFERENCED_PARAMETER(SNode);
UNREFERENCED_PARAMETER(Now);
Link->Metric = 1;
}
//* MiniportPersistControl
//
// Writes configuration parameters to the registry.
//
NTSTATUS
MiniportPersistControl(
MiniportAdapter *VA,
VRR_CONTROL_VIRTUAL_ADAPTER *Control)
{
NTSTATUS Status;
HANDLE DeviceKey;
HANDLE Key;
//
// We do not need to validate the configuration parameters.
// They will be validated after being read from the registry.
//
Status = IoOpenDeviceRegistryKey(VA->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
GENERIC_READ,
&DeviceKey);
if (! NT_SUCCESS(Status))
return Status;
Status = OpenRegKey(&Key, DeviceKey, L"Parameters", OpenRegKeyCreate);
ZwClose(DeviceKey);
if (! NT_SUCCESS(Status))
return Status;
if (Control->Snooping != (uint)-1) {
Status = SetRegDWORDValue(Key, L"Snooping", Control->Snooping);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->ArtificialDrop != (uint)-1) {
Status = SetRegDWORDValue(Key, L"ArtificialDrop",
Control->ArtificialDrop);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->Crypto != (uint)-1) {
Status = SetRegDWORDValue(Key, L"Crypto", Control->Crypto);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (VRR_KEY_PRESENT(Control->CryptoKeyMAC)) {
Status = SetRegBinaryValue(Key, L"CryptoKeyMAC",
Control->CryptoKeyMAC, sizeof Control->CryptoKeyMAC);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (VRR_KEY_PRESENT(Control->CryptoKeyAES)) {
Status = SetRegBinaryValue(Key, L"CryptoKeyAES",
Control->CryptoKeyAES, sizeof Control->CryptoKeyAES);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->LinkTimeout != (uint)-1) {
Status = SetRegDWORDValue(Key, L"LinkTimeout", Control->LinkTimeout);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricType != (uint)-1) {
Status = SetRegDWORDValue(Key, L"MetricType", Control->MetricType);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
switch (Control->MetricType) {
case METRIC_TYPE_PKTPAIR:
if (Control->MetricParams.PktPair.Alpha != (uint)-1) {
Status = SetRegDWORDValue(Key, L"Alpha",
Control->MetricParams.PktPair.Alpha);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.PktPair.ProbePeriod != (uint)-1) {
Status = SetRegDWORDValue(Key, L"ProbePeriod",
Control->MetricParams.PktPair.ProbePeriod);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.PktPair.PenaltyFactor != (uint)-1) {
Status = SetRegDWORDValue(Key, L"PenaltyFactor",
Control->MetricParams.PktPair.PenaltyFactor);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
break;
case METRIC_TYPE_WCETT:
if (Control->MetricParams.Wcett.Alpha != (uint)-1) {
Status = SetRegDWORDValue(Key, L"Alpha",
Control->MetricParams.Wcett.Alpha);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.Wcett.PenaltyFactor != (uint)-1) {
Status = SetRegDWORDValue(Key, L"PenaltyFactor",
Control->MetricParams.Wcett.PenaltyFactor);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.Wcett.LossInterval != (uint)-1) {
Status = SetRegDWORDValue(Key, L"LossInterval",
Control->MetricParams.Wcett.LossInterval);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.Wcett.Beta != (uint)-1) {
Status = SetRegDWORDValue(Key, L"Beta",
Control->MetricParams.Wcett.Beta);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.Wcett.PktPairProbePeriod != (uint)-1) {
Status = SetRegDWORDValue(Key, L"PktPairProbePeriod",
Control->MetricParams.Wcett.PktPairProbePeriod);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
if (Control->MetricParams.Wcett.PktPairMinOverProbes != (uint)-1) {
Status = SetRegDWORDValue(Key, L"PktPairMinOverProbes",
Control->MetricParams.Wcett.PktPairMinOverProbes);
if (! NT_SUCCESS(Status))
goto CloseReturn;
}
break;
}
Status = STATUS_SUCCESS;
CloseReturn:
ZwClose(Key);
return Status;
}
//* MiniportReadControl
//
// Reads configuration parameters from the registry.
//
void
MiniportReadControl(
MiniportAdapter *VA,
VRR_CONTROL_VIRTUAL_ADAPTER *Control)
{
NTSTATUS Status;
HANDLE DeviceKey;
HANDLE Key;
//
// We must always return an initialized Control structure.
//
VRR_INIT_CONTROL_VIRTUAL_ADAPTER(Control);
Status = IoOpenDeviceRegistryKey(VA->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
GENERIC_READ,
&DeviceKey);
if (! NT_SUCCESS(Status))
return;
Status = OpenRegKey(&Key, DeviceKey, L"Parameters", OpenRegKeyCreate);
ZwClose(DeviceKey);
if (! NT_SUCCESS(Status))
return;
//
// Read configuration parameters.
//
(void) GetRegDWORDValue(Key, L"Snooping",
(PULONG)&Control->Snooping);
(void) GetRegDWORDValue(Key, L"ArtificialDrop",
(PULONG)&Control->ArtificialDrop);
(void) GetRegDWORDValue(Key, L"Crypto",
(PULONG)&Control->Crypto);
(void) GetRegBinaryValue(Key, L"CryptoKeyMAC",
Control->CryptoKeyMAC, sizeof Control->CryptoKeyMAC);
(void) GetRegBinaryValue(Key, L"CryptoKeyAES",
Control->CryptoKeyAES, sizeof Control->CryptoKeyAES);
(void) GetRegDWORDValue(Key, L"LinkTimeout",
(PULONG)&Control->LinkTimeout);
(void) GetRegDWORDValue(Key, L"MetricType",
(PULONG)&Control->MetricType);
switch (Control->MetricType) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -