d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * VBoxNetUDP - IntNet UDP Client Routines.
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2009-2010 Oracle Corporation
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* Header Files *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync*******************************************************************************/
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Checks if the head of the receive ring is a UDP packet matching the given
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * criteria.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @returns Pointer to the data if it matches.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pBuf The IntNet buffers.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param uDstPort The destination port to match.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pDstMac The destination address to match if
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * VBOXNETUDP_MATCH_UNICAST is specied.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param fFlags Flags indicating what to match and some debug stuff.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * See VBOXNETUDP_MATCH_*.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pHdrs Where to return the pointers to the headers.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Optional.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pcb Where to return the size of the data on success.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncvoid *VBoxNetUDPMatch(PINTNETBUF pBuf, unsigned uDstPort, PCRTMAC pDstMac, uint32_t fFlags, PVBOXNETUDPHDRS pHdrs, size_t *pcb)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Clear return values so we can return easier on mismatch.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Valid IntNet Ethernet frame?
9127c416edfd6f9266e387f7abd7aa9904eecbc9vboxsync PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&pBuf->Recv);
9127c416edfd6f9266e387f7abd7aa9904eecbc9vboxsync const void *pvFrame = IntNetHdrGetFramePtr(pHdr, pBuf);
6dd8f5023a9ba7588212331db90059553136fe33vboxsync if (!PDMNetGsoIsValid(pGso, cbFrame, cbFrame - sizeof(*pGso)))
6dd8f5023a9ba7588212331db90059553136fe33vboxsync /** @todo IPv6 UDP support, goes for this entire function really. Not really
6dd8f5023a9ba7588212331db90059553136fe33vboxsync * important yet since this is currently only used by the DHCP server. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Dump if to stderr/log if that's wanted. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTStrmPrintf(g_pStdErr, "frame: cb=%04x dst=%.6Rhxs src=%.6Rhxs type=%04x%s\n",
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync cbFrame, &pEthHdr->DstMac, &pEthHdr->SrcMac, RT_BE2H_U16(pEthHdr->EtherType),
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync !memcmp(&pEthHdr->DstMac, pDstMac, sizeof(*pDstMac)) ? " Mine!" : "");
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Ethernet matching.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Ethernet min frame size. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Match Ethertype: IPV4? */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /** @todo VLAN tagging? */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pEthHdr->EtherType != RT_H2BE_U16_C(RTNET_ETHERTYPE_IPV4))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Match destination address (ethernet) */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync || memcmp(&pEthHdr->DstMac, pDstMac, sizeof(pEthHdr->DstMac)))
6dd8f5023a9ba7588212331db90059553136fe33vboxsync * If we're working on a GSO frame, we need to make sure the length fields
6dd8f5023a9ba7588212331db90059553136fe33vboxsync * are set correctly (they are usually set to 0).
bad918bbc587b87deb80ad29dafb6f837b0c538evboxsync PDMNetGsoPrepForDirectUse(pGso, (void *)pvFrame, cbFrame, PDMNETCSUMTYPE_NONE);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * IP validation and matching.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Protocol: UDP */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Valid IPv4 header? */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync size_t const offIpHdr = (uintptr_t)pIpHdr - (uintptr_t)pEthHdr;
6dd8f5023a9ba7588212331db90059553136fe33vboxsync if (!RTNetIPv4IsHdrValid(pIpHdr, cbFrame - offIpHdr, cbFrame - offIpHdr, !pGso /*fChecksum*/))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * UDP matching and validation.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* Destination port */
6dd8f5023a9ba7588212331db90059553136fe33vboxsync /* Validate the UDP header according to flags. */
6dd8f5023a9ba7588212331db90059553136fe33vboxsync size_t offUdpHdr = (uintptr_t)pUdpHdr - (uintptr_t)pEthHdr;
6dd8f5023a9ba7588212331db90059553136fe33vboxsync if (fFlags & (VBOXNETUDP_MATCH_CHECKSUM | VBOXNETUDP_MATCH_REQUIRE_CHECKSUM))
6dd8f5023a9ba7588212331db90059553136fe33vboxsync if (!RTNetIPv4IsUDPValid(pIpHdr, pUdpHdr, pUdpHdr + 1, cbFrame - offUdpHdr, true /*fChecksum*/))
6dd8f5023a9ba7588212331db90059553136fe33vboxsync if (!RTNetIPv4IsUDPSizeValid(pIpHdr, pUdpHdr, cbFrame - offUdpHdr))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * We've got a match!
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/** Internal worker for VBoxNetUDPUnicast and VBoxNetUDPBroadcast. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncstatic int vboxnetudpSend(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETADDRIPV4 SrcIPv4Addr, PCRTMAC pSrcMacAddr, unsigned uSrcPort,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETADDRIPV4 DstIPv4Addr, PCRTMAC pDstMacAddr, unsigned uDstPort,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* the Ethernet header */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync EtherHdr.EtherType = RT_H2BE_U16_C(RTNET_ETHERTYPE_IPV4);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* the IP header */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync unsigned cbIdHdr = RT_UOFFSETOF(RTNETIPV4, ip_options);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync IpHdr.ip_len = RT_H2BE_U16((uint16_t)(cbData + sizeof(RTNETUDP) + cbIdHdr));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* the UDP bit */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync UdpHdr.uh_ulen = RT_H2BE_U16((uint16_t)(cbData + sizeof(RTNETUDP)));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync UdpHdr.uh_sum = 0; /* pretend checksumming is disabled */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync UdpHdr.uh_sum = RTNetIPv4UDPChecksum(&IpHdr, &UdpHdr, pvData);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* the payload */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* send it */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return VBoxNetIntIfSend(pSession, hIf, pBuf, RT_ELEMENTS(aSegs), &aSegs[0], true /* fFlush */);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Sends an unicast UDP packet.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @returns VBox status code.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pSession The support driver session handle.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param hIf The interface handle.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pBuf The interface buffer.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param SrcIPv4Addr The source IPv4 address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pSrcMacAddr The source MAC address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param uSrcPort The source port number.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param DstIPv4Addr The destination IPv4 address. Can be broadcast.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pDstMacAddr The destination MAC address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param uDstPort The destination port number.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pvData The data payload.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param cbData The size of the data payload.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncint VBoxNetUDPUnicast(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETADDRIPV4 SrcIPv4Addr, PCRTMAC pSrcMacAddr, unsigned uSrcPort,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETADDRIPV4 DstIPv4Addr, PCRTMAC pDstMacAddr, unsigned uDstPort,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Sends a broadcast UDP packet.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @returns VBox status code.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pSession The support driver session handle.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param hIf The interface handle.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pBuf The interface buffer.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param SrcIPv4Addr The source IPv4 address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pSrcMacAddr The source MAC address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param uSrcPort The source port number.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param uDstPort The destination port number.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pvData The data payload.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param cbData The size of the data payload.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncint VBoxNetUDPBroadcast(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTNETADDRIPV4 SrcIPv4Addr, PCRTMAC pSrcMacAddr, unsigned uSrcPort,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync MacBrdCast.au16[0] = MacBrdCast.au16[1] = MacBrdCast.au16[2] = UINT16_C(0xffff);