tstIntNet-1.cpp revision c27d83bdf2f07df38b7d86b70609a0bf86316f16
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VBox - Testcase for internal networking, simple NetFlt trunk creation.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * available from http://www.virtualbox.org. This file is free software;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * you can redistribute it and/or modify it under the terms of the GNU
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * General Public License (GPL) as published by the Free Software
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * additional information or have any questions.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Header Files *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include "../Pcap.h"
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Global Variables *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic int g_cErrors = 0;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic bool g_fDhcpReply = false;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Error reporting wrapper.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pErrStrm The stream to write the error message to. Can be NULL.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pszFormat The message format string.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param ... Format arguments.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic void tstIntNetError(PRTSTREAM pErrStrm, const char *pszFormat, ...)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Parses a frame an runs in thru the RTNet validation code so it gets
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * some exercise.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pvFrame Pointer to the ethernet frame.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param cbFrame The size of the ethernet frame.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pErrStrm The error stream.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic void tstIntNetTestFrame(void const *pvFrame, size_t cbFrame, PRTSTREAM pErrStrm)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Ethernet header.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PCRTNETETHERHDR pEtherHdr = (PCRTNETETHERHDR)pvFrame;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return tstIntNetError(pErrStrm, "cbFrame=%#x <= %#x (ether)\n", cbFrame, sizeof(*pEtherHdr));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync uint8_t const *pbCur = (uint8_t const *)(pEtherHdr + 1);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return tstIntNetError(pErrStrm, "RTNetIPv4IsHdrValid failed\n");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /** @todo ICMP? */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!RTNetIPv4IsUDPValid(pIpHdr, pUdpHdr, pUdpHdr + 1, cbLeft))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return tstIntNetError(pErrStrm, "RTNetIPv4IsUDPValid failed\n");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (RT_BE2H_U16(pUdpHdr->uh_dport) == RTNETIPV4_PORT_BOOTPS)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!RTNetIPv4IsDHCPValid(pUdpHdr, pDhcp, cbLeft, NULL))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return tstIntNetError(pErrStrm, "RTNetIPv4IsDHCPValid failed\n");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!RTNetIPv4IsTCPValid(pIpHdr, pTcpHdr, cbLeft, NULL, cbLeft))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return tstIntNetError(pErrStrm, "RTNetIPv4IsTCPValid failed\n");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync //case RTNET_ETHERTYPE_IPV6:
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Writes a frame packet to the buffer.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @returns VBox status code.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pBuf The buffer.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pRingBuf The ring buffer to read from.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pvFrame The frame to write.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param cbFrame The size of the frame.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @remark This is the same as INTNETRingWriteFrame and drvIntNetRingWriteFrame.
8c99dcd207cf5b7bee01f95fbe19728a94076f94vboxsyncstatic int tstIntNetWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, const void *pvFrame, uint32_t cbFrame)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Validate input.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Try fit it all before the end of the buffer.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Try fit the frame at the start of the buffer.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * (The header fits before the end of the buffer because of alignment.)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (offRead - pRingBuf->offStart > cb) /* not >= ! */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * The reader is ahead of the writer, try fit it into that space.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* (it didn't fit) */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /** @todo stats */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Transmits one frame after appending the CRC.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param hIf The interface handle.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pSession The session.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pBuf The shared interface buffer.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pvFrame The frame without a crc.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param cbFrame The size of it.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pFileRaw The file to write the raw data to (optional).
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pFileText The file to write a textual packet summary to (optional).
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic void doXmitFrame(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PINTNETBUF pBuf, void *pvFrame, size_t cbFrame, PRTSTREAM pFileRaw, PRTSTREAM pFileText)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTStrmPrintf(pFileText, "%3RU64.%09u: cb=%04x dst=%.6Rhxs src=%.6Rhxs type=%04x Send!\n",
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync NanoTS / 1000000000, (uint32_t)(NanoTS % 1000000000),
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync cbFrame, &pEthHdr->SrcMac, &pEthHdr->DstMac, RT_BE2H_U16(pEthHdr->EtherType));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Run in thru the frame validator to test the RTNet code.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Write the frame and push the queue.
fc85d12482b4d79dd2dfd0989b9730433c7a45cbvboxsync * Don't bother with dealing with overflows like DrvIntNet does, because
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * it's not supposed to happen here in this testcase.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync int rc = tstIntNetWriteFrame(pBuf, &pBuf->Send, pvFrame, cbFrame);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PcapStreamFrame(pFileRaw, g_StartTS, pvFrame, cbFrame, 0xffff);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTPrintf("tstIntNet-1: tstIntNetWriteFrame failed, %Rrc; cbFrame=%d pBuf->cbSend=%d\n", rc, cbFrame, pBuf->cbSend);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync rc = SUPCallVMMR0Ex(NIL_RTR0PTR, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTPrintf("tstIntNet-1: SUPCallVMMR0Ex(,VMMR0_DO_INTNET_IF_SEND,) failed, rc=%Rrc\n", rc);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Does the transmit test.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param hIf The interface handle.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pSession The session.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pBuf The shared interface buffer.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pSrcMac The mac address to use as source.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pFileRaw The file to write the raw data to (optional).
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param pFileText The file to write a textual packet summary to (optional).
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic void doXmitTest(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PINTNETBUF pBuf, PCRTMAC pSrcMac, PRTSTREAM pFileRaw, PRTSTREAM pFileText)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0];
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Create a simple DHCP broadcast request.
doXmitFrame(hIf, pSession, pBuf, &abFrame[0], (uint8_t *)(pDhcpMsg + 1) - (uint8_t *)&abFrame[0], pFileRaw, pFileText);
static void doPacketSniffing(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PINTNETBUF pBuf, uint32_t cMillies,
g_cErrors++;
if (pFileRaw)
if (pFileText)
g_fDhcpReply = true;
g_cErrors++;
"%3RU64.%09u: cOtherPkts=%RU32 cArpPkts=%RU32 cIpv4Pkts=%RU32 cTcpPkts=%RU32 cUdpPkts=%RU32 cDhcpPkts=%RU32\n",
RTR3Init(false, 0);
#ifdef RT_OS_DARWIN
bool fMacSharing = false;
bool fPromiscuous = false;
bool fSniffer = false;
bool fXmitTest = false;
int rc;
int ch;
switch (ch)
RTPrintf("tstIntNet-1: Interface name is too long (max %d chars): %s\n", INTNET_MAX_TRUNK_NAME - 1, pszIf);
fMacSharing = true;
RTPrintf("tstIntNet-1: Network name is too long (max %d chars): %s\n", INTNET_MAX_NETWORK_NAME - 1, pszNetwork);
fPromiscuous = true;
fSniffer = true;
fXmitTest = true;
if (fPromiscuous)
if (pFileRaw)
if (fXmitTest)
if (fSniffer)
RTPrintf("tstIntNet-1: Error! The DHCP server didn't reply... (Perhaps you don't have one?)\n", rc);
g_cErrors++;
RTPrintf("tstIntNet-1: SUPCallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc);
g_cErrors++;
RTPrintf("tstIntNet-1: SUPCallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc);
g_cErrors++;
RTPrintf("tstIntNet-1: SUPCallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_RING3_BUFFER,) failed, rc=%Rrc\n", rc);
g_cErrors++;
g_cErrors++;
if (pFileRaw)
if (!g_cErrors)
return !!g_cErrors;