📄 protocol.c
字号:
#if 0
ReleasePA(PA);
#endif
}
//* ProtocolTransmit
//
// Send a packet. The packet already has an Ethernet header.
//
void
ProtocolTransmit(
ProtocolAdapter *PA,
NDIS_PACKET *Packet)
{
EtherHeader UNALIGNED *Ether;
NDIS_STATUS Status;
InterlockedIncrement((PLONG)&PA->VirtualAdapter->CountXmit);
//
// We never want the physical adapter to loopback.
//
Packet->Private.Flags = NDIS_FLAGS_DONT_LOOPBACK;
//
// Our sender initializes the Ethernet destination.
//
Ether = (EtherHeader UNALIGNED *) NdisFirstBuffer(Packet)->MappedSystemVa;
RtlCopyMemory(Ether->Source, PA->Address, IEEE_802_ADDR_LENGTH);
Ether->Type = ETYPE_MSFT;
//
// Our sender initializes PC(Packet)->TransmitComplete.
// The packet holds a reference for the physical adapter.
//
#if 0
AddRefPA(PA);
#endif
PC(Packet)->PA = PA;
InterlockedIncrementHighWater((PLONG)&PA->CountSentOutstanding,
(PLONG)&PA->MaxSentOutstanding);
if (PA->ReceiveOnly) {
//
// This is adapter is configured to only receive.
// This simplifies testing of asymmetric links.
//
Status = NDIS_STATUS_FAILURE;
}
else {
//
// Send the packet. NDIS will call ProtocolTransmitComplete
// if the send completes asynchronously.
//
InterlockedIncrement((PLONG)&PA->PacketsSent);
NdisSend(&Status, PA->Handle, Packet);
}
if (Status != NDIS_STATUS_PENDING) {
//
// The send finished synchronously,
// so we call the completion handler.
//
ProtocolTransmitComplete((NDIS_HANDLE)PA, Packet, Status);
}
}
//* ProtocolResetComplete
//
// Called by NDIS when a reset completes.
//
void
ProtocolResetComplete(
NDIS_HANDLE Handle, // Binding handle.
NDIS_STATUS Status) // Final status of command.
{
ProtocolAdapter *PA = (ProtocolAdapter *)Handle;
UNREFERENCED_PARAMETER(Status);
UNREFERENCED_PARAMETER(PA);
KdPrint(("VRR!ProtocolResetComplete(VA %p PA %p)\n",
PA->VirtualAdapter, PA));
}
//* ProtocolRequestComplete
//
// Called by NDIS when an NdisRequest completes.
// We block on all requests, so we'll just wake up
// whoever's blocked on this request.
//
//
void
ProtocolRequestComplete(
NDIS_HANDLE Handle, // Binding handle.
PNDIS_REQUEST Context, // Request that completed.
NDIS_STATUS Status) // Final status of requested command.
{
ProtocolRequest *Request = (ProtocolRequest *) Context;
UNREFERENCED_PARAMETER(Handle);
//
// Signal the completion of a generic synchronous request.
// See ProtocolRequestHelper and NeighborCacheTimeout.
//
if (Request->ContextOnStack == TRUE) {
//
// The caller of NdisRequest is blocked. Context is in
// caller's stack frame and NdisRequest has written to
// a buffer that is not visible from here.
//
Request->Status = Status;
KeSetEvent(&Request->Event, 0, FALSE);
}
else {
//
// The caller of NdisRequest cannot block and has allocated
// memory for Context and Buffer that we must release.
//
KIRQL OldIrql;
KeAcquireSpinLock(&Request->PA->SibInfoLock, &OldIrql);
RtlCopyMemory(&Request->PA->SibInfo, Request->Buffer, sizeof(MSRCSibTableInfo));
KeReleaseSpinLock(&Request->PA->SibInfoLock, OldIrql);
ExFreePool(Request->Buffer);
ExFreePool(Request);
}
}
//* ProtocolFreePacket
//
// Frees a packet allocated by ProtocolReceive.
//
void
ProtocolFreePacket(
ProtocolAdapter *PA,
NDIS_PACKET *Packet)
{
NDIS_BUFFER *Buffer;
void *Data;
Buffer = NdisFirstBuffer(Packet);
VRRASSERT((Buffer != NULL) && (Buffer->Next == NULL));
VRRASSERT(Buffer->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL);
Data = Buffer->MappedSystemVa;
NdisFreePacket(Packet);
NdisFreeBuffer(Buffer);
ExFreePool(Data);
InterlockedDecrement((PLONG)&PA->CountRecvOutstanding);
}
//* ProtocolTransferDataComplete
//
// Called by NDIS when a transfer data completes.
// We now have a complete packet.
//
void
ProtocolTransferDataComplete(
NDIS_HANDLE Handle, // Binding handle.
PNDIS_PACKET Packet, // The packet used for the Transfer Data (TD).
NDIS_STATUS Status, // Final status of command.
uint BytesCopied) // Number of bytes copied.
{
ProtocolAdapter *PA = (ProtocolAdapter *)Handle;
NDIS_BUFFER *Buffer;
UNREFERENCED_PARAMETER(BytesCopied);
KdPrint(("VRR!ProtocolTransferDataComplete(VA %p PA %p) -> %x\n",
PA->VirtualAdapter, PA, Status));
//
// Undo the NdisAdjustBuffer in ProtocolReceive.
//
Buffer = NdisFirstBuffer(Packet);
NdisAdjustBuffer(Buffer,
(uchar *)Buffer->MappedSystemVa - sizeof(EtherHeader),
Buffer->ByteCount + sizeof(EtherHeader));
if (Status == NDIS_STATUS_SUCCESS) {
//
// We have the packet data so receive the packet.
//
MiniportReceivePacket(PA->VirtualAdapter, PA,
Packet, ProtocolFreePacket);
}
else {
//
// Free the packet.
//
ProtocolFreePacket(PA, Packet);
}
}
//* ProtocolReceive
//
// Called by NDIS when data arrives from L2 driver.
// Note that newer NDIS drivers are likely to call ProtocolReceivePacket to
// indicate data arrival instead of this routine.
//
// The status code tells NDIS whether or not we took the packet.
//
NDIS_STATUS
ProtocolReceive(
NDIS_HANDLE ProtocolBindingContext,
NDIS_HANDLE MacReceiveContext,
void *HeaderBuffer,
uint HeaderBufferSize,
void *LookAheadBuffer,
uint LookAheadBufferSize,
uint PacketSize)
{
ProtocolAdapter *PA = (ProtocolAdapter *) ProtocolBindingContext;
EtherHeader UNALIGNED *Ether;
NDIS_PACKET *Packet;
NDIS_BUFFER *Buffer;
void *Data;
uint UNALIGNED *Code;
NDIS_STATUS Status;
UNREFERENCED_PARAMETER(HeaderBufferSize);
//
// Because we only bind to Ethernets.
//
VRRASSERT(HeaderBufferSize == sizeof *Ether);
Ether = (EtherHeader UNALIGNED *) HeaderBuffer;
//
// Check both the EtherType and the following code value
// to ensure that we only receive VRR packets.
//
if (Ether->Type != ETYPE_MSFT)
return NDIS_STATUS_NOT_RECOGNIZED;
if ((PacketSize < sizeof *Code) || (LookAheadBufferSize < sizeof *Code))
return NDIS_STATUS_NOT_RECOGNIZED;
Code = (uint UNALIGNED *) LookAheadBuffer;
if (*Code != VRR_CODE)
return NDIS_STATUS_NOT_RECOGNIZED;
InterlockedIncrement((PLONG)&PA->PacketsReceived);
//
// Allocate non-paged pool to hold the packet data.
//
Data = ExAllocatePool(NonPagedPool, sizeof *Ether + PacketSize);
if (Data == NULL)
return NDIS_STATUS_RESOURCES;
//
// Allocate a packet structure.
//
NdisAllocatePacket(&Status, &Packet, PA->PacketPool);
if (Status != NDIS_STATUS_SUCCESS) {
InterlockedIncrement((PLONG)&PA->CountPacketPoolFailure);
ExFreePool(Data);
return Status;
}
//
// Allocate a packet buffer.
//
VrrNdisAllocateBuffer(&Status, &Buffer, PA->BufferPool,
Data, sizeof *Ether + PacketSize);
if (Status != NDIS_STATUS_SUCCESS) {
NdisFreePacket(Packet);
ExFreePool(Data);
return Status;
}
NdisChainBufferAtFront(Packet, Buffer);
InterlockedIncrementHighWater((PLONG)&PA->CountRecvOutstanding,
(PLONG)&PA->MaxRecvOutstanding);
//
// Do we have the entire packet?
//
if (LookAheadBufferSize < PacketSize) {
uint Transferred;
InterlockedIncrement((PLONG)&PA->PacketsReceivedTD);
//
// Copy the Ethernet header.
//
RtlCopyMemory(Data, HeaderBuffer, sizeof *Ether);
//
// We must asynchronously transfer the packet data.
// To do this we must adjust the buffer to move past
// the Ethernet header.
//
NdisAdjustBuffer(Buffer, (uchar *)Data + sizeof *Ether, PacketSize);
NdisTransferData(&Status, PA->Handle, MacReceiveContext,
0, PacketSize, Packet, &Transferred);
if (Status != NDIS_STATUS_PENDING) {
//
// The transfer completed synchronously.
//
ProtocolTransferDataComplete(ProtocolBindingContext,
Packet, Status, Transferred);
}
}
else {
InterlockedIncrement((PLONG)&PA->PacketsReceivedFlat);
//
// We already have access to the packet data.
//
RtlCopyMemory(Data, HeaderBuffer, sizeof *Ether);
RtlCopyMemory((uchar *)Data + sizeof *Ether,
LookAheadBuffer, PacketSize);
MiniportReceivePacket(PA->VirtualAdapter, PA,
Packet, ProtocolFreePacket);
}
return NDIS_STATUS_SUCCESS;
}
//* ProtocolReceiveComplete
//
// Called by NDIS after some number of receives.
// In some sense, it indicates 'idle time'.
//
void
ProtocolReceiveComplete(
NDIS_HANDLE Handle) // Binding handle.
{
UNREFERENCED_PARAMETER(Handle);
}
typedef struct ProtocolMediaConnectContext {
PIO_WORKITEM Item;
ProtocolAdapter *PA;
} ProtocolMediaConnectContext;
//* ProtocolQueryRadioConfiguration
//
// Uses ProtocolRequestHelper to query the channel and bandwidth
// of the physical adapter.
//
// Called in a thread context, not at DPC level.
//
void
ProtocolQueryRadioConfiguration(
ProtocolAdapter *PA)
{
NDIS_STATUS Status;
//
// Note that a burst of media-connect events can lead to races
// with multiple simultaneous ProtocolQueryRadioConfiguration
// executions. We need the mutex to ensure that after the last
// media-connect, the adapter configuration stabilizes with
// correct Channel and Bandwidth values.
//
ExAcquireFastMutex(&PA->Mutex);
if (! PA->BandwidthConfigured) {
uint Speed;
//
// Query the maximum link bandwidth.
//
Status = ProtocolRequestHelper(PA, NdisRequestQueryInformation,
OID_GEN_LINK_SPEED,
&Speed, sizeof Speed,
NULL);
if (Status != NDIS_STATUS_SUCCESS) {
//
// Use 10Mbs as a default.
//
Speed = 100000;
}
//
// The OID returns the speed value in 100 bps units.
//
PA->Bandwidth = WcettEncodeBandwidth(Speed * 100);
}
if (! PA->ChannelConfigured) {
NDIS_802_11_CONFIGURATION Radio;
//
// Use Channel zero as a default.
//
PA->Channel = 0;
//
// Query the radio configuration.
// NB: If the radio is still associating, this query will fail!
//
Status = ProtocolRequestHelper(PA, NdisRequestQueryInformation,
OID_802_11_CONFIGURATION,
&Radio, sizeof Radio,
NULL);
if (Status == NDIS_STATUS_SUCCESS) {
//
// The OID returns the channel in kHz.
// Convert to a channel number.
//
switch (Radio.DSConfig) {
#define Case24GhzChannel(ch) \
case ((ch * 5) + 2407) * 1000: \
PA->Channel = ch; \
break
Case24GhzChannel(1);
Case24GhzChannel(2);
Case24GhzChannel(3);
Case24GhzChannel(4);
Case24GhzChannel(5);
Case24GhzChannel(6);
Case24GhzChannel(7);
Case24GhzChannel(8);
Case24GhzChannel(9);
Case24GhzChannel(10);
Case24GhzChannel(11);
#define Case5GhzChannel(ch) \
case ((ch * 5) + 5000) * 1000: \
PA->Channel = ch; \
break
Case5GhzChannel(36);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -