📄 vbridge.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
VBridge.c
Abstract:
Notes:
This file implements or manage the shared ethernet resources
for EDBG and VMINI.
--*/
#include <windows.h>
#include "nkintr.h"
#include "kitlprot.h"
//
// Useful defines..
//
#define PRINTMSG(cond, printf_exp) ((void)((cond)?(PRINTF printf_exp) : 0))
#define PLUSPLUS(a, max) \
(((a+1)>=max) ? 0x00 : (a+1))
#define ETH_IS_BROADCAST(Address) \
(((PUCHAR)(Address))[0] == ((UCHAR)0xff))
#define MAX_8023_PDU 1514
//
// From ndis.h
//
#define ETH_COMPARE_NETWORK_ADDRESSES_EQ(_A,_B, _Result) \
{ \
if ((*(ULONG UNALIGNED *)&(_A)[2] == \
*(ULONG UNALIGNED *)&(_B)[2]) && \
(*(USHORT UNALIGNED *)(_A) == \
*(USHORT UNALIGNED *)(_B))) \
{ \
*(_Result) = 1; \
} \
else \
{ \
*(_Result) = 0; \
} \
}
//
// Buffer manipulations..
//
#define TX_BUFFERS_DWORD 0x4000 / sizeof(DWORD)
#define RX_BUFFERS_DWORD 0x4000 / sizeof(DWORD)
#define HEADER_SIGNATURE 0x12345678
#define FLAG_PRODUCED 0x00000001 // This buffer is produced..
#define FLAG_CONSUMED 0x00000002 // This buffer is consumed..
#define FLAG_SKIP_BUFFER 0x00000004 // No data skip to next one.
typedef struct _PACKET_HEADER
{
#ifdef DEBUG
DWORD dwSignature; // Signature of header..
#endif
DWORD dwFlag; // Miscellaneous flags..
UCHAR *pucNextBuffer; // The next chunk..
DWORD dwCurrentSize; // Zero ? go to next chunk..
} PACKET_HEADER, *PPACKET_HEADER;
PUCHAR pucTxProducer; // Manipulated by User Code.
PUCHAR pucTxConsumer; // Manipulated by Kernel Code.
PUCHAR pucRxProducer; // Manipulated by Kernel Code.
PUCHAR pucRxConsumer; // Manipulated by User Code.
PUCHAR pucTxMax; // For convenience..
PUCHAR pucTxMin;
PUCHAR pucRxMax; // For convenience..
PUCHAR pucRxMin;
ULONG TxBuffers[TX_BUFFERS_DWORD];
ULONG RxBuffers[RX_BUFFERS_DWORD];
DWORD dwCurrentPacketFilter; // Current VMini filter mode..
UCHAR EDBGMacAddress[6]; // Address that VMini should use..
BOOL bValidAddress = FALSE; // Whether EDBGMacAddress is valid.
BOOL bWarnNoMacDone = FALSE; // One time warning to user.
HANDLE hRxInterruptEvent = NULL;
HANDLE hPKDRxInterruptEvent = NULL;
BOOL g_bResetBuffer = FALSE; // Set in IOCTL_VBRIDGE_WILD_CARD_RESET_BUFFER.
//
// Forward decl..
//
extern void
OEMWriteDebugByte(BYTE ucChar);
extern void
SendVMiniPackets(void);
//
// For debugging purposes..
//
static void OutputString(const unsigned char *s)
{
while (*s)
{
if (*s == '\n')
OEMWriteDebugByte('\r');
OEMWriteDebugByte(*s++);
}
}
static void pOutputByte(unsigned char c)
{
OEMWriteDebugByte(c);
}
static void pOutputNumHex(unsigned long n, long depth)
{
if (depth)
depth--;
if ((n & ~0xf) || depth)
{
pOutputNumHex(n >> 4, depth);
n &= 0xf;
}
if (n < 10)
{
pOutputByte((unsigned char)(n + '0'));
}
else
{
pOutputByte((unsigned char)(n - 10 + 'A'));
}
}
static void pOutputNumDecimal(unsigned long n)
{
if (n >= 10)
{
pOutputNumDecimal(n / 10);
n %= 10;
}
pOutputByte((unsigned char)(n + '0'));
}
////////////////////////////////////////////////////////////////////////////////
// PRINTF()
// Returns length of formatted string
// Input:
// Pointer to string to return formatted output.
// User must ensure that buffer is large enough.
//
// const unsigned char * | sz,... |
// Format String:
//
// @flag Format string | type
// @flag u | unsigned
// @flag d | int
// @flag c | char
// @flag s | string
// @flag x | 4-bit hex number
// @flag B | 8-bit hex number
// @flag H | 16-bit hex number
// @flag X | 32-bit hex number
//
void
PRINTF(
const unsigned char *sz,
...
)
{
unsigned char c;
va_list vl;
va_start(vl, sz);
while (*sz)
{
c = *sz++;
switch (c)
{
case (unsigned char)'%':
c = *sz++;
switch (c)
{
case 'x':
pOutputNumHex(va_arg(vl, unsigned long), 0);
break;
case 'B':
pOutputNumHex(va_arg(vl, unsigned long), 2);
break;
case 'H':
pOutputNumHex(va_arg(vl, unsigned long), 4);
break;
case 'X':
pOutputNumHex(va_arg(vl, unsigned long), 8);
break;
case 'd':
{
long l;
l = va_arg(vl, long);
if (l < 0)
{
pOutputByte('-');
l = - l;
}
pOutputNumDecimal((unsigned long)l);
}
break;
case 'u':
pOutputNumDecimal(va_arg(vl, unsigned long));
break;
case 's':
OutputString(va_arg(vl, char *));
break;
case '%':
pOutputByte('%');
break;
case 'c':
c = va_arg(vl, unsigned char);
pOutputByte(c);
break;
default:
pOutputByte(' ');
break;
}
break;
case '\n':
pOutputByte('\r');
// fall through
default:
pOutputByte(c);
}
}
pOutputByte(0);
va_end(vl);
} // PRINTF()
////////////////////////////////////////////////////////////////////////////////
// Misc utility functions.
//
void VBridgeDisplayHex (BYTE data)
{
if (data < 0x10)
PRINTMSG(1, ("0"));
PRINTMSG (1, ("%x ", data));
} // DisplayHex()
void VBridgeDumpMemory (PBYTE pSource, DWORD dwLength)
{
int i = 0;
PRINTMSG (1, ("+---- MEM DUMP (%d bytes)----+\r\n", dwLength));
PRINTMSG (1, ("0x%x: ", pSource));
while (dwLength--)
{
VBridgeDisplayHex (*pSource++);
if (++i == 16)
{
i = 0;
PRINTMSG (1, ("\r\n0x%x: ", pSource));
}
}
PRINTMSG (1, ("\r\n\r\n"));
} // DumpMemory()
////////////////////////////////////////////////////////////////////////////////
// EthAddressCmp()
//
// Routine Description:
//
// Compares two MAC addresses and returns TRUE if they are the same.
// Start from LSB as it will perform less comparison.
//
// Arguments:
//
// AddressA :: Address to be compared.
// AddressB :: Address to be compared.
// usLength :: Length of the address..
//
// Return Value:
//
// TRUE if compared, FALSE otherwise..
//
BOOL
EthAddressCmp (PBYTE AddressA, PBYTE AddressB, SHORT usLength)
{
int i = 0;
while (i < usLength)
{
if (AddressA[i] != AddressB[i])
return FALSE;
i++;
}
return TRUE;
} // EthAddressCmp()
////////////////////////////////////////////////////////////////////////////////
// ProduceBuffer()
//
// 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 User code.
// For Rx case, it will be called by Kernel code.
//
// dwSize :: Buffer size requested..
//
// Return Value:
//
// Null if no buffer available, otherwise pointer to buffer to be used.
//
PUCHAR
ProduceBuffer(BOOL bIsTx, DWORD dwSize)
{
PUCHAR *ppucProducer;
PUCHAR *ppucBufferStart;
PUCHAR *ppucBufferEnd;
PUCHAR *ppucConsumer;
PACKET_HEADER *pPacketHeader;
DWORD dwTotalSize;
DWORD dwAddThis;
//
// Our buffers are always DWORD align..
//
dwTotalSize = dwSize + sizeof(PACKET_HEADER);
dwAddThis = dwTotalSize % 4;
if (dwAddThis)
dwTotalSize += (4 - dwAddThis);
if (bIsTx)
{
ppucProducer = &pucTxProducer;
ppucBufferStart = &pucTxMin;
ppucBufferEnd = &pucTxMax;
ppucConsumer = &pucTxConsumer;
}
else
{
ppucProducer = &pucRxProducer;
ppucBufferStart = &pucRxMin;
ppucBufferEnd = &pucRxMax;
ppucConsumer = &pucRxConsumer;
}
//
// First stop is to check we won't overshoot consumer..
//
if ((*ppucConsumer > *ppucProducer) &&
(*ppucProducer + dwTotalSize >= *ppucConsumer))
{
return NULL;
}
//
// Make sure we don't wrap..
// And after this requested buffer, we have at least
// enough space for PACKET_HEADER at the end of this buffer for SKIP
// BUFFER..
//
if ((*ppucProducer + dwTotalSize) > (*ppucBufferEnd - sizeof(PACKET_HEADER)))
{
PRINTMSG (0,
("Producer = [0x%x] : TotalSize = [%d] : BufferEnd[0x%x]\r\n",
*ppucProducer,
dwTotalSize,
*ppucBufferEnd));
//
// Nop, and if the consumer is not at the beginning of the
// buffer, then it's safe for us to advance the producer there..
//
if (*ppucConsumer == *ppucBufferStart)
{
//
// Consumer is hogging at the beginning..
//
return NULL;
}
//
// Okay, consumer is not there, so it's safe to mark this as
// SKIP buffer..
//
pPacketHeader = (PPACKET_HEADER) *ppucProducer;
#ifdef DEBUG
pPacketHeader->dwSignature = HEADER_SIGNATURE;
#endif
pPacketHeader->dwFlag = FLAG_SKIP_BUFFER;
pPacketHeader->pucNextBuffer = *ppucBufferStart;
//
// It's safe to move the producer pointer now..
//
PRINTMSG (0, ("SKIP produced [0x%x].\r\n",
*ppucProducer));
*ppucProducer = *ppucBufferStart;
//
// Now make sure we can fit it without overshooting consumer..
//
if ((*ppucConsumer > *ppucProducer) &&
(*ppucProducer + dwTotalSize >= *ppucConsumer))
{
//
// Too Bad.. not enough space..
//
PRINTMSG (0,
("-- Producer = [0x%x] : TotalSize = [%d] : BufferEnd[0x%x]\r\n",
*ppucProducer,
dwTotalSize,
*ppucBufferEnd));
return NULL;
}
}
//
// By now we are guarantee that the buffer will not wrap..
// And we definitely have space..
//
pPacketHeader = (PPACKET_HEADER) *ppucProducer;
#ifdef DEBUG
pPacketHeader->dwSignature = HEADER_SIGNATURE;
#endif
//
// Packet not ready until the caller calls ProduceBufferDone().
//
pPacketHeader->dwFlag = 0x00;
pPacketHeader->pucNextBuffer = *ppucProducer + dwTotalSize;
pPacketHeader->dwCurrentSize = dwSize;
//
// Okay, it's safe to move the producer pointer now..
// The owner of this buffer is on its own now, it will need to
// call ProduceBufferDone() to let the consumer know that it can now
// be consumed. Failure to do so will block the flow!!!
//
*ppucProducer = *ppucProducer + dwTotalSize;
return ((PUCHAR)pPacketHeader + sizeof(PACKET_HEADER));
} // ProduceBuffer()
////////////////////////////////////////////////////////////////////////////////
// ProduceBufferDone()
//
// Routine Description:
//
// This function will mark the buffer to be ready for consumption.
//
// Arguments:
//
// bIsTx :: Whether it is TX buffer or RX buffer.
// pucBuffer :: Points to buffer obtained in ProduceBuffer()
//
// Return Value:
//
// None.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -