⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 protocol.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 4 页
字号:
#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 + -