d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/* $Id$ */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/** @file
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * VBoxNetARP - IntNet ARP Client Routines.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/*
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2009-2010 Oracle Corporation
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * available from http://www.virtualbox.org. This file is free software;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * you can redistribute it and/or modify it under the terms of the GNU
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * General Public License (GPL) as published by the Free Software
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/*******************************************************************************
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync* Header Files *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync*******************************************************************************/
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#define LOG_GROUP LOG_GROUP_DEFAULT
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#include "VBoxNetLib.h"
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#include <iprt/string.h>
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#include <VBox/intnetinline.h>
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#include <VBox/log.h>
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Deal with ARP queries.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @returns true if ARP.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pSession The support driver session.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param hIf The internal network interface handle.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pBuf The internal network interface buffer.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pMacAddr Our MAC address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param IPv4Addr Our IPv4 address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncbool VBoxNetArpHandleIt(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf, PCRTMAC pMacAddr, RTNETADDRIPV4 IPv4Addr)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync{
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
6dd8f5023a9ba7588212331db90059553136fe33vboxsync * Valid IntNet Ethernet frame? Skip GSO, no ARP in there.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
9127c416edfd6f9266e387f7abd7aa9904eecbc9vboxsync PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&pBuf->Recv);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if ( !pHdr
3c086cee27d5216042cc045c009537485c0339b5vboxsync || pHdr->u8Type != INTNETHDR_TYPE_FRAME)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync size_t cbFrame = pHdr->cbFrame;
9127c416edfd6f9266e387f7abd7aa9904eecbc9vboxsync const void *pvFrame = IntNetHdrGetFramePtr(pHdr, pBuf);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Arp frame?
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pEthHdr->EtherType != RT_H2N_U16_C(RTNET_ETHERTYPE_ARP))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if ( ( pEthHdr->DstMac.au16[0] != 0xffff
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || pEthHdr->DstMac.au16[1] != 0xffff
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || pEthHdr->DstMac.au16[2] != 0xffff)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync && ( pEthHdr->DstMac.au16[0] != pMacAddr->au16[0]
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || pEthHdr->DstMac.au16[1] != pMacAddr->au16[1]
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || pEthHdr->DstMac.au16[2] != pMacAddr->au16[2])
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync )
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (cbFrame < sizeof(RTNETARPIPV4) + sizeof(RTNETETHERHDR))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync PCRTNETARPHDR pArpHdr = (PCRTNETARPHDR)(pEthHdr + 1);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pArpHdr->ar_htype != RT_H2N_U16_C(RTNET_ARP_ETHER))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pArpHdr->ar_hlen != sizeof(RTMAC))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pArpHdr->ar_ptype != RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pArpHdr->ar_plen != sizeof(RTNETADDRIPV4))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return false;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* It's ARP, alright. Anything we need to do something about. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync PCRTNETARPIPV4 pArp = (PCRTNETARPIPV4)pArpHdr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync switch (pArp->Hdr.ar_oper)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync case RT_H2N_U16_C(RTNET_ARPOP_REQUEST):
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync case RT_H2N_U16_C(RTNET_ARPOP_REVREQUEST):
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync case RT_H2N_U16_C(RTNET_ARPOP_INVREQUEST):
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync break;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync default:
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return true;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Deal with the queries.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETARPIPV4 Reply;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync switch (pArp->Hdr.ar_oper)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* 'Who has ar_tpa? Tell ar_spa.' */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync case RT_H2N_U16_C(RTNET_ARPOP_REQUEST):
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pArp->ar_tpa.u != IPv4Addr.u)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return true;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.Hdr.ar_oper = RT_H2N_U16_C(RTNET_ARPOP_REPLY);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync break;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync case RT_H2N_U16_C(RTNET_ARPOP_REVREQUEST):
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if ( pArp->ar_tha.au16[0] != pMacAddr->au16[0]
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || pArp->ar_tha.au16[1] != pMacAddr->au16[1]
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || pArp->ar_tha.au16[2] != pMacAddr->au16[2])
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return true;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.Hdr.ar_oper = RT_H2N_U16_C(RTNET_ARPOP_REVREPLY);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync break;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync case RT_H2N_U16_C(RTNET_ARPOP_INVREQUEST):
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /** @todo RTNET_ARPOP_INVREQUEST */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return true;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync //Reply.Hdr.ar_oper = RT_H2N_U16_C(RTNET_ARPOP_INVREPLY);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync //break;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Complete the reply and send it.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.Hdr.ar_htype = RT_H2N_U16_C(RTNET_ARP_ETHER);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.Hdr.ar_ptype = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.Hdr.ar_hlen = sizeof(RTMAC);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.Hdr.ar_plen = sizeof(RTNETADDRIPV4);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.ar_sha = *pMacAddr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.ar_spa = IPv4Addr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.ar_tha = pArp->ar_sha;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Reply.ar_tpa = pArp->ar_spa;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETETHERHDR EthHdr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync EthHdr.DstMac = pArp->ar_sha;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync EthHdr.SrcMac = *pMacAddr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync EthHdr.EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_ARP);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync uint8_t abTrailer[60 - sizeof(Reply) - sizeof(EthHdr)];
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync memset(abTrailer, '\0', sizeof(abTrailer));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync INTNETSEG aSegs[3];
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync aSegs[0].cb = sizeof(EthHdr);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync aSegs[0].pv = &EthHdr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync aSegs[1].pv = &Reply;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync aSegs[1].cb = sizeof(Reply);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync aSegs[2].pv = &abTrailer[0];
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync aSegs[2].cb = sizeof(abTrailer);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync VBoxNetIntIfSend(pSession, hIf, pBuf, RT_ELEMENTS(aSegs), &aSegs[0], true /* fFlush */);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return true;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync