📄 vbridge.c
字号:
void
ProduceBufferDone(BOOL bIsTx, PUCHAR pucBuffer)
{
PACKET_HEADER *pPacketHeader;
pPacketHeader = (PPACKET_HEADER)(pucBuffer - sizeof(PACKET_HEADER));
ASSERT(pPacketHeader->dwSignature == HEADER_SIGNATURE);
//
// Off it goes..
//
pPacketHeader->dwFlag = FLAG_PRODUCED;
} // ProduceBufferDone()
////////////////////////////////////////////////////////////////////////////////
// ConsumeBuffer()
//
// Routine Description:
//
// This function will give a chunck of buffer for the caller.
//
// Arguments:
//
// bIsTx :: Whether it is TX buffer or RX buffer.
// For Tx case, it will be called by Kernel code.
// For Rx case, it will be called by User code.
//
// pdwSize :: [o] size of the buffer returned..
//
// Return Value:
//
// Null if no buffer available, otherwise pointer to buffer to be used.
//
PUCHAR
ConsumeBuffer(BOOL bIsTx, DWORD *pdwSize)
{
PUCHAR *ppucProducer;
PUCHAR *ppucBufferStart;
PUCHAR *ppucBufferEnd;
PUCHAR *ppucConsumer;
PACKET_HEADER *pPacketHeader;
if (bIsTx)
{
ppucProducer = &pucTxProducer;
ppucConsumer = &pucTxConsumer;
ppucBufferStart = &pucTxMin;
ppucBufferEnd = &pucTxMax;
}
else
{
ppucProducer = &pucRxProducer;
ppucConsumer = &pucRxConsumer;
ppucBufferStart = &pucRxMin;
ppucBufferEnd = &pucRxMax;
}
//
// Anything at all ???
//
if (*ppucProducer == *ppucConsumer)
return NULL;
//
// Something avail.. SKIP if it's SKIP buffer..
//
pPacketHeader = (PACKET_HEADER *)*ppucConsumer;
ASSERT(pPacketHeader->dwSignature == HEADER_SIGNATURE);
if (pPacketHeader->dwFlag & FLAG_SKIP_BUFFER)
{
PRINTMSG (0, ("SKIP consumed [0x%x].\r\n",
*ppucConsumer));
*ppucConsumer = pPacketHeader->pucNextBuffer;
//
// Now, check if producer has produced after the SKIP buffer
//
if (*ppucProducer == *ppucConsumer)
return NULL;
}
//
// By now we may have data..
//
pPacketHeader = (PACKET_HEADER *)*ppucConsumer;
ASSERT(pPacketHeader->dwSignature == HEADER_SIGNATURE);
//
// See if it is ready for consumption..
//
if (!(pPacketHeader->dwFlag & FLAG_PRODUCED))
{
//
// Buffer not yet cooked..
//
return NULL;
}
//
// This buffer is now in the process of being consumed..
//
pPacketHeader->dwFlag &= ~FLAG_PRODUCED;
*pdwSize = pPacketHeader->dwCurrentSize;
return ((PUCHAR)pPacketHeader + sizeof(PACKET_HEADER));
} // ConsumeBuffer()
////////////////////////////////////////////////////////////////////////////////
// ConsumeBufferDone()
//
// Routine Description:
//
// This function will mark the chunk of buffer ready for production usage..
//
// Arguments:
//
// bIsTx :: Whether it is TX buffer or RX buffer.
// pucBuffer :: Points to buffer obtained in ProduceBuffer()
//
// Return Value:
//
// None.
//
void
ConsumeBufferDone(BOOL bIsTx, PUCHAR pucBuffer)
{
PACKET_HEADER *pPacketHeader;
PUCHAR *ppucConsumer;
if (bIsTx)
{
ppucConsumer = &pucTxConsumer;
}
else
{
ppucConsumer = &pucRxConsumer;
}
pPacketHeader = (PPACKET_HEADER)(pucBuffer - sizeof(PACKET_HEADER));
//
// This means we require only one outstanding consumer at anyone time..
//
ASSERT(*ppucConsumer == (pucBuffer - sizeof(PACKET_HEADER)));
ASSERT(pPacketHeader->dwSignature == HEADER_SIGNATURE);
pPacketHeader->dwFlag = FLAG_CONSUMED;
*ppucConsumer = pPacketHeader->pucNextBuffer;
} // ConsumeBufferDone()
////////////////////////////////////////////////////////////////////////////////
// SetInterruptEvent()
//
// Routine Description:
//
// Copied here from coredll..
//
// Arguments:
//
// idInt :: the SYSINTR value to trigger..
//
// Return Value:
//
// None.
//
BOOL SetInterruptEvent(DWORD idInt)
{
long mask;
long pend;
long *ptrPend;
if ((idInt < SYSINTR_DEVICES) || (idInt >= SYSINTR_MAXIMUM))
return FALSE;
idInt -= SYSINTR_DEVICES;
mask = 1 << idInt;
ptrPend = (long*)(UserKInfo[KINX_KDATA_ADDR]+KINFO_OFFSET) + KINX_PENDEVENTS;
do {
pend = *ptrPend;
if (pend & mask)
return TRUE; // The bit is already set, so all done.
} while (InterlockedTestExchange(ptrPend, pend, pend|mask) != pend);
return TRUE;
} // SetInterruptEvent()
/* -------------------------------------------------------------------------- */
/* Start of VBridge exported functions. */
/* -------------------------------------------------------------------------- */
////////////////////////////////////////////////////////////////////////////////
// VBridgeInit()
//
// Routine Description:
//
// Called to initialize all the VBridge related variables.
// This should be called by OEMEthInit() code, and hence it will be running
// in KERNEL mode.
//
// Arguments:
//
// None.
//
// Return Value:
//
// TRUE :: Successful.
// FALSE :: Otherwise..
//
BOOL
VBridgeInit()
{
//
// Use UNCACHED regions..
//
pucTxProducer = (PUCHAR)((DWORD)&TxBuffers[0] | 0x20000000);
pucTxConsumer = (PUCHAR)((DWORD)&TxBuffers[0] | 0x20000000);
pucRxProducer = (PUCHAR)((DWORD)&RxBuffers[0] | 0x20000000);
pucRxConsumer = (PUCHAR)((DWORD)&RxBuffers[0] | 0x20000000);
pucTxMax = (PUCHAR)((DWORD)&TxBuffers[TX_BUFFERS_DWORD] | 0x20000000);
pucTxMin = pucTxProducer;
pucRxMax = (PUCHAR)((DWORD)&RxBuffers[RX_BUFFERS_DWORD] | 0x20000000);
pucRxMin = pucRxProducer;
PRINTMSG (1, ("VBridgeInit()...TX = [%d] bytes -- Rx = [%d] bytes\r\n",
pucTxMax - pucTxProducer,
pucRxMax - pucRxProducer));
PRINTMSG (1, ("Tx buffer [0x%x] to [0x%x].\r\n",
pucTxMin,
pucTxMax));
PRINTMSG (1, ("Rx buffer [0x%x] to [0x%x].\r\n",
pucRxMin,
pucRxMax));
//
// Start off with VMINI having getting nothing..
//
dwCurrentPacketFilter = 0x00;
g_bResetBuffer = FALSE;
return TRUE;
} // VBridgeInit()
////////////////////////////////////////////////////////////////////////////////
// VBridgeKGetOneTxBuffer()
//
// Routine Description:
//
// Called by kernel mode code to query if there is any packet to be sent.
// This function will return the pointer to the buffer (containing ethernet
// packet) and the length of the actual data.
//
// Arguments:
//
// ppucBuffer :: Points to the start of the ethernet packet.
// puiLength :: Length of the packet..
//
// Return Value:
//
// TRUE :: There is data to be sent.
// FALSE :: No data to be sent.
//
BOOL
VBridgeKGetOneTxBuffer(
PUCHAR *ppucBuffer,
UINT *puiLength)
{
if (g_bResetBuffer)
VBridgeInit();
if (ppucBuffer == NULL || puiLength == NULL)
{
PRINTMSG (1, ("VBridgeKGetOneTxBuffer() Err! [0x%x] [0x%x]\r\n",
ppucBuffer,
puiLength));
return FALSE;
}
*ppucBuffer = ConsumeBuffer(TRUE, puiLength);
if (*ppucBuffer)
{
PRINTMSG (0, ("> "));
return TRUE;
}
else
return FALSE;
} // VBridgeKGetOneTxBuffer()
////////////////////////////////////////////////////////////////////////////////
// VBridgeKGetOneTxBufferComplete()
//
// Routine Description:
//
// This must follow VBridgeKGetOneTxBuffer().
//
// Arguments:
//
// pucBuffer :: Pointer to the buffer that kernel is returning to
// VBridge.
//
// Return Values:
//
// None.
//
// Mode:
//
// Kernel mode only.
//
//
void
VBridgeKGetOneTxBufferComplete(PUCHAR pucBuffer)
{
if (g_bResetBuffer)
VBridgeInit();
if (pucBuffer == NULL)
{
PRINTMSG (1,
("VBridgeKGetOneTxBufferComplete(), NULL pucBuffer!\r\n"));
return;
}
ConsumeBufferDone(TRUE, pucBuffer);
} // VBridgeKGetOneTxBufferComplete()
////////////////////////////////////////////////////////////////////////////////
// VBridgeKIndicateOneRxBuffer()
//
// Routine Description:
//
// This is called by kernel code to insert an RX ethernet packet for
// VMini.
//
// Arguments:
//
// pBuffer :: Points to the the rx'ed ethernet buffer.
// uiLength :: Length of the packet.
// bSwappable :: IGNORED (no longer supported)..
//
// Return Values:
//
// The original buffer pointer, contents are copied locally.
//
// Mode:
// Kernel Mode only.
//
#include <pshpack1.h>
typedef struct IPHeaderFormatTag
{
BYTE bVersionLength;
BYTE bTypeOfService;
UINT16 cwTotalLength;
UINT16 wIdentification;
UINT16 wFragment;
BYTE bTimeToLive;
BYTE bProtocol;
UINT16 wCRC;
DWORD dwSrcIP;
DWORD dwDestIP;
//
// Options can go in here, then comes the data
//
} IPHeaderFormat, *pIPHeaderFormat;
typedef struct UDPHeaderFormatTag
{
UINT16 wSrcPort;
UINT16 wDestPort;
UINT16 cwTotalUDPLength;
UINT16 wCRC;
//
// Then comes data..
//
} UDPHeaderFormat, *pUDPHeaderFormat;
typedef struct ENetHeader
{
uchar eh_daddr[6];
uchar eh_saddr[6];
ushort eh_type;
} ENetHeaderFormat, *pENetHeaderFormat;
typedef struct SNAPHeader
{
uchar eh_daddr[6];
uchar eh_saddr[6];
uchar sh_dsap;
uchar sh_ssap;
uchar sh_ctl;
uchar sh_protid[3];
ushort sh_etype;
} SNAPHeaderFormat, *pSNAPHeaderFormat;
#include <poppack.h>
#define MIN_ETYPE 0x0600 // Minimum valid Ethertype
#define IP_TYPE 0x0800 // IP frame.
#define SNAP_SAP 0xAA
#define SNAP_UI 0x3
#define PROTOCOL_UDP 0x11
#define EDBG_UDP_PORT 0x03d5
#define DHCP_CLIENT_PORT 0x0044
#ifndef net_short
#define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
#endif
#pragma optimize("",off)
PUCHAR
VBridgeKIndicateOneRxBuffer(PUCHAR pBuffer, UINT uiLength, BOOL bSwappable, BOOL *pbTaken)
{
PUCHAR pucKernelBuffer;
////////////////////////////////////////////////////////////////////////////
// We share MAC address with the EDBG, don't want to eat EDBG
// packet.
// The following packet types will be return to EDBG:
// - Broadcast.
// - Any DHCP packet directed to us.
// - Any EDBG packet.
//
IPHeaderFormat UNALIGNED *pIPHeader;
UDPHeaderFormat UNALIGNED *pUDPHeader;
ENetHeaderFormat UNALIGNED *pEnetHeader;
KITL_HDR UNALIGNED *pKitlHdr;
USHORT usEType;
BOOL bBroadcast = FALSE; // is it Broadcast???
BOOL bDhcp = FALSE; // is it DHCP packet???
//
// Platform may have bug not calling VBridgeKSetLocalMacAddress()...
// Pass all the packets to EDBG..
//
if (g_bResetBuffer)
VBridgeInit();
if (pBuffer == NULL || uiLength > MAX_8023_PDU || pbTaken == NULL)
{
PRINTMSG(1,
("VBridgeKIndicateOneRxBuffer() Err [0x%x] [0x%x] [0x%x]\r\n",
pBuffer,
uiLength,
pbTaken));
return FALSE;
}
if (!bValidAddress)
{
if (!bWarnNoMacDone)
{
PRINTMSG (1,
("** WARNING!!! ** Device MAC addr not set to VBridge..\r\n"));
bWarnNoMacDone = TRUE;
}
*pbTaken = FALSE;
return pBuffer;
}
PRINTMSG (0, ("Rx: [%x%x%x%x%x%x] --> [%x%x%x%x%x%x] [%x%x]\r\n",
pBuffer[6],
pBuffer[7],
pBuffer[8],
pBuffer[9],
pBuffer[10],
pBuffer[11],
pBuffer[0],
pBuffer[1],
pBuffer[2],
pBuffer[3],
pBuffer[4],
pBuffer[5],
pBuffer[12],
pBuffer[13]));
//
// Immediately toss the packet if it is > max Ethernet MTU..
//
if (uiLength > MAX_8023_PDU)
{
//
// a corrupt packet, don't even pass it to EDBG.
// Pretend we consume it..
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -