📄 sr.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"
//
// Prototypes for internal helper functions.
//
static SRPacket *FillSRPacket(SRPacket *SRP, VRRHeader *VRR);
static uint SROptionLength(const SRPacket *SRP);
//* SRFreeOptionList
//
// Helper function for SRPacketFree.
// Frees a list of options.
//
void
SRFreeOptionList(InternalOption *List)
{
InternalOption *Opt;
while ((Opt = List) != NULL) {
List = Opt->Next;
ExFreePool(Opt);
}
}
//* SRPacketFree
//
// Deallocate a SRPacket and all its sub-allocations.
//
void
SRPacketFree(SRPacket *SRP)
{
SRFreeOptionList((InternalOption *)SRP->ackreq);
SRFreeOptionList((InternalOption *)SRP->ack);
SRFreeOptionList((InternalOption *)SRP->Probe);
SRFreeOptionList((InternalOption *)SRP->ProbeReply);
SRFreeOptionList((InternalOption *)SRP->VrrHello);
SRFreeOptionList((InternalOption *)SRP->VrrSetup);
SRFreeOptionList((InternalOption *)SRP->VrrTearDown);
SRFreeOptionList((InternalOption *)SRP->VrrSetupReq);
if (SRP->Packet != NULL) {
VRRASSERT(SRP->FreePacket != NULL);
(*SRP->FreePacket)(SRP->PA, SRP->Packet);
}
ExFreePool(SRP);
}
//* SRPacketMAC
//
// Calculates the MAC value for an VRR packet.
//
static void
SRPacketMAC(
MiniportAdapter *VA,
uchar *MAC,
NDIS_PACKET *Packet)
{
if (VA->Crypto) {
//
// The normal case - real security.
// We truncate the HMAC-SHA1 output to VRR_MAC_LENGTH bytes.
//
#if BUILD_CRYPTO // DDK
CryptoMAC(VA->CryptoKeyMAC, MAC, VRR_MAC_LENGTH,
Packet, sizeof(EtherHeader) + VRR_MAC_SKIP);
#endif
}
else {
//
// Security is disabled, but we still want version checking.
// We just send the per-adapter key (which is not a strong secret).
//
#if BUILD_CRYPTO
VRRASSERT(CRYPTO_KEY_MAC_LENGTH == VRR_MAC_LENGTH);
#endif
RtlCopyMemory(MAC, VA->CryptoKeyMAC, VRR_MAC_LENGTH);
}
}
//* SRPacketFromPkt
//
// Parses an NDIS packet into an SRPacket.
//
NDIS_STATUS
SRPacketFromPkt(
MiniportAdapter *VA,
NDIS_PACKET *Packet,
SRPacket **pSRP)
{
uchar MAC[VRR_MAC_LENGTH];
SRPacket *SRP;
void *OrigHeader;
EtherHeader *OrigEther;
VRRHeader *OrigVRR;
NDIS_BUFFER *OrigBuffer;
uint OrigBufferLength;
uint HeaderLength;
uint OrigPacketLength;
InternalAcknowledgementRequest *AckReq;
InternalAcknowledgement *Ack;
InternalProbe *Pro;
InternalProbeReply *ProRep;
InternalVrrHello *VrrH;
InternalVrrSetup *VrrS;
InternalVrrTearDown *VrrT;
InternalVrrSetupReq *VrrSR;
//
// NB: Below code assumes the entire VRR header is contiguous.
//
NdisGetFirstBufferFromPacket(Packet, &OrigBuffer, &OrigHeader,
&OrigBufferLength, &OrigPacketLength);
VRRASSERT(OrigBufferLength <= OrigPacketLength);
if (OrigBufferLength < sizeof(EtherHeader) + sizeof(VRRHeader))
return NDIS_STATUS_BUFFER_TOO_SHORT;
OrigEther = (EtherHeader *) OrigHeader;
OrigVRR = (VRRHeader *) (OrigEther + 1);
HeaderLength = (sizeof(EtherHeader) +
sizeof(VRRHeader) +
OrigVRR->HeaderLength);
if (OrigBufferLength < HeaderLength)
return NDIS_STATUS_BUFFER_TOO_SHORT;
if (OrigVRR->HopCount >= VRR_MAX_HOPCOUNT) {
VrrKdPrint("SRPacketFromPkt: drop pkt(s,d) HopCount exceeded",
OrigVRR->Source, OrigVRR->Dest);
InterlockedIncrement(&VA->CountHopCountExceeded);
return NDIS_STATUS_INVALID_PACKET;
}
//
// Verify the MAC.
//
SRPacketMAC(VA, MAC, Packet);
if (! RtlEqualMemory(MAC, OrigVRR->MAC, VRR_MAC_LENGTH)) {
InterlockedIncrement((PLONG)&VA->CountRecvBadMAC);
return NDIS_STATUS_INVALID_PACKET;
}
SRP = ExAllocatePool(NonPagedPool, sizeof *SRP);
if (SRP == NULL)
return NDIS_STATUS_RESOURCES;
RtlZeroMemory(SRP, sizeof *SRP);
//
// Parse the VRR header options.
//
SRP = FillSRPacket(SRP, OrigVRR);
if (SRP == NULL) {
//
// Illegal packet format. FillSRPacket freed SRP.
//
return NDIS_STATUS_INVALID_PACKET;
}
//
// Extract fields from from the VRR header.
//
RtlCopyMemory(SRP->Source, OrigVRR->Source, sizeof(VirtualAddress));
RtlCopyMemory(SRP->Dest, OrigVRR->Dest, sizeof(VirtualAddress));
RtlCopyMemory(SRP->Origin, OrigVRR->Origin, sizeof(VirtualAddress));
SRP->FrameSeqNo = RtlUlongByteSwap(OrigVRR->FrameSeqNo);
SRP->HopCount = OrigVRR->HopCount;
//
// Save information about the original packet.
// NB: Calling SRPacketFree after doing this
// and before our caller initializes SRP->FreePacket
// will cause a bugcheck.
//
SRP->Packet = Packet;
SRP->PacketLength = OrigPacketLength;
SRP->PayloadOffset = HeaderLength;
//
// Save some info for later.
//
RtlCopyMemory(SRP->EtherDest, OrigEther->Dest, SR_ADDR_LEN);
RtlCopyMemory(SRP->EtherSource, OrigEther->Source, SR_ADDR_LEN);
RtlCopyMemory(SRP->IV, OrigVRR->IV, VRR_IV_LENGTH);
//
// Increment our counters.
//
for (AckReq = SRP->ackreq; AckReq != NULL; AckReq = AckReq->next)
InterlockedIncrement((PLONG)&VA->CountRecvAckRequest);
for (Ack = SRP->ack; Ack != NULL; Ack = Ack->next)
InterlockedIncrement((PLONG)&VA->CountRecvAck);
for (Pro = SRP->Probe; Pro != NULL; Pro = Pro->Next)
InterlockedIncrement((PLONG)&VA->CountRecvProbe);
for (ProRep = SRP->ProbeReply; ProRep != NULL; ProRep = ProRep->Next)
InterlockedIncrement((PLONG)&VA->CountRecvProbeReply);
for (VrrH = SRP->VrrHello; VrrH != NULL; VrrH = VrrH->Next)
InterlockedIncrement((PLONG)&VA->CountRecvHello);
for (VrrS = SRP->VrrSetup; VrrS != NULL; VrrS = VrrS->Next)
InterlockedIncrement((PLONG)&VA->CountRecvSetup);
for (VrrT = SRP->VrrTearDown; VrrT != NULL; VrrT = VrrT->Next)
InterlockedIncrement((PLONG)&VA->CountRecvTearDown);
for (VrrSR = SRP->VrrSetupReq; VrrSR != NULL; VrrSR = VrrSR->Next) {
InterlockedIncrement((PLONG)&VA->CountRecvSetupReq);
if (SR_DIRECTION_BITS(VrrSR->Opt.Type) == VRR_SR_DIRECT_LHS)
InterlockedIncrement((PLONG)&VA->CountRecvSRleft);
if (SR_DIRECTION_BITS(VrrSR->Opt.Type) == VRR_SR_DIRECT_RHS)
InterlockedIncrement((PLONG)&VA->CountRecvSRright);
}
*pSRP = SRP;
return NDIS_STATUS_SUCCESS;
}
//* CheckPacket
//
// This is a combination of SRPacketFromPkt and FillSRPacket
// that just sanity-checks the packet, for debugging purposes.
//
NDIS_STATUS
CheckPacket(
MiniportAdapter *VA,
NDIS_PACKET *Packet)
{
uchar MAC[VRR_MAC_LENGTH];
void *OrigHeader;
EtherHeader *OrigEther;
VRRHeader *OrigVRR;
NDIS_BUFFER *OrigBuffer;
uint OrigBufferLength;
uint HeaderLength;
uint OrigPacketLength;
VRROption *Walk;
uint Left;
//
// NB: Below code assumes the entire VRR header is contiguous.
//
NdisGetFirstBufferFromPacket(Packet, &OrigBuffer, &OrigHeader,
&OrigBufferLength, &OrigPacketLength);
VRRASSERT(OrigBufferLength <= OrigPacketLength);
if (OrigBufferLength < sizeof(EtherHeader) + sizeof(VRRHeader)) {
KdPrint(("VRR!CheckPacket: header truncated\n"));
return NDIS_STATUS_BUFFER_TOO_SHORT;
}
OrigEther = (EtherHeader *) OrigHeader;
OrigVRR = (VRRHeader *) (OrigEther + 1);
HeaderLength = (sizeof(EtherHeader) +
sizeof(VRRHeader) +
OrigVRR->HeaderLength);
if (OrigBufferLength < HeaderLength) {
KdPrint(("VRR!CheckPacket: options truncated\n"));
return NDIS_STATUS_BUFFER_TOO_SHORT;
}
//
// Verify the MAC.
//
SRPacketMAC(VA, MAC, Packet);
if (! RtlEqualMemory(MAC, OrigVRR->MAC, VRR_MAC_LENGTH)) {
KdPrint(("VRR!CheckPacket: bad MAC\n"));
return NDIS_STATUS_INVALID_PACKET;
}
//
// Walk the options and verify them.
//
Walk = (VRROption *)(OrigVRR + 1);
Left = OrigVRR->HeaderLength;
while (Left != 0) {
//
// Verify that we have enough data to match what the option
// itself claims is present.
//
if ((Left < sizeof *Walk) ||
(Left < sizeof *Walk + Walk->optDataLen)) {
KdPrint(("VRR!CheckPacket: bad option length\n"));
return NDIS_STATUS_INVALID_PACKET;
}
switch (Walk->optionType) {
case VRR_OPTION_TYPE_ACKREQ:
if (Walk->optDataLen != ACK_REQUEST_LEN) {
KdPrint(("VRR!CheckPacket: bad ack req\n"));
return NDIS_STATUS_INVALID_PACKET;
}
break;
case VRR_OPTION_TYPE_ACK:
if (Walk->optDataLen != ACKNOWLEDGEMENT_LEN) {
KdPrint(("VRR!CheckPacket: bad ack\n"));
return NDIS_STATUS_INVALID_PACKET;
}
break;
case VRR_OPTION_TYPE_PROBE:
//
// First, make sure that we have enough
// data left to read ProbeType correctly.
//
if (Walk->optDataLen < PROBE_LEN) {
KdPrint(("VRR!CheckPacket: bad probe\n"));
return NDIS_STATUS_INVALID_PACKET;
}
switch (((Probe *)Walk)->ProbeType) {
case METRIC_TYPE_PKTPAIR:
if (Walk->optDataLen != PROBE_LEN) {
KdPrint(("VRR!CheckPacket: bad pktpair\n"));
return NDIS_STATUS_INVALID_PACKET;
}
break;
default:
KdPrint(("VRR!CheckPacket: bad probe type\n"));
return NDIS_STATUS_INVALID_PACKET;
}
break;
case VRR_OPTION_TYPE_PROBEREPLY:
//
// First, make sure that we have enough
// data left to read ProbeType correctly.
//
if (Walk->optDataLen < PROBE_REPLY_LEN) {
KdPrint(("VRR!CheckPacket: bad probe reply\n"));
return NDIS_STATUS_INVALID_PACKET;
}
switch (((Probe *)Walk)->ProbeType) {
case METRIC_TYPE_PKTPAIR:
if (Walk->optDataLen != PROBE_REPLY_LEN + sizeof(PRPktPair)) {
KdPrint(("VRR!CheckPacket: bad pktpair reply\n"));
return NDIS_STATUS_INVALID_PACKET;
}
break;
default:
KdPrint(("VRR!CheckPacket: bad probe reply type\n"));
return NDIS_STATUS_INVALID_PACKET;
}
break;
case VRR_OPTION_TYPE_HELLO:
//
// VrrHello options must be large enough to hold Hello preamble.
//
if (Walk->optDataLen < VRRHELLO_LEN(0)) {
KdPrint(("VRR!CheckPacket: VrrHello length < sizeof(Hello preamble)\n"));
return NDIS_STATUS_INVALID_PACKET;
}
//
// VrrHello NCEList length must be an integral multiple of NCEList * n.
//
if (Walk->optDataLen > VRRHELLO_LEN(0)) {
uint NCEBuff = Walk->optDataLen - (sizeof(VrrHello) - sizeof(VRROption));
if (0 != NCEBuff % sizeof(VrrHelloNCE)) {
KdPrint(("VRR!CheckPacket: VrrHello trailer not multiple of NCE info\n"));
return NDIS_STATUS_INVALID_PACKET;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -