Exemplo n.º 1
0
/**
 * Deal with ARP queries.
 *
 * @returns true if ARP.
 *
 * @param   pSession        The support driver session.
 * @param   hIf             The internal network interface handle.
 * @param   pBuf            The internal network interface buffer.
 * @param   pMacAddr        Our MAC address.
 * @param   IPv4Addr        Our IPv4 address.
 */
bool VBoxNetArpHandleIt(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf, PCRTMAC pMacAddr, RTNETADDRIPV4 IPv4Addr)
{
    /*
     * Valid IntNet Ethernet frame? Skip GSO, no ARP in there.
     */
    PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&pBuf->Recv);
    if (   !pHdr
        || pHdr->u16Type != INTNETHDR_TYPE_FRAME)
        return false;

    size_t          cbFrame = pHdr->cbFrame;
    const void     *pvFrame = IntNetHdrGetFramePtr(pHdr, pBuf);
    PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;

    /*
     * Arp frame?
     */
    if (pEthHdr->EtherType != RT_H2N_U16_C(RTNET_ETHERTYPE_ARP))
        return false;
    if (   (   pEthHdr->DstMac.au16[0] != 0xffff
            || pEthHdr->DstMac.au16[1] != 0xffff
            || pEthHdr->DstMac.au16[2] != 0xffff)
        && (   pEthHdr->DstMac.au16[0] != pMacAddr->au16[0]
            || pEthHdr->DstMac.au16[1] != pMacAddr->au16[1]
            || pEthHdr->DstMac.au16[2] != pMacAddr->au16[2])
       )
        return false;
    if (cbFrame < sizeof(RTNETARPIPV4) + sizeof(RTNETETHERHDR))
        return false;

    PCRTNETARPHDR pArpHdr = (PCRTNETARPHDR)(pEthHdr + 1);
    if (pArpHdr->ar_htype != RT_H2N_U16_C(RTNET_ARP_ETHER))
        return false;
    if (pArpHdr->ar_hlen != sizeof(RTMAC))
        return false;
    if (pArpHdr->ar_ptype != RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4))
        return false;
    if (pArpHdr->ar_plen != sizeof(RTNETADDRIPV4))
        return false;

    /* It's ARP, alright. Anything we need to do something about. */
    PCRTNETARPIPV4 pArp = (PCRTNETARPIPV4)pArpHdr;
    switch (pArp->Hdr.ar_oper)
    {
        case RT_H2N_U16_C(RTNET_ARPOP_REQUEST):
        case RT_H2N_U16_C(RTNET_ARPOP_REVREQUEST):
        case RT_H2N_U16_C(RTNET_ARPOP_INVREQUEST):
            break;
        default:
            return true;
    }

    /*
     * Deal with the queries.
     */
    RTNETARPIPV4 Reply;
    switch (pArp->Hdr.ar_oper)
    {
        /* 'Who has ar_tpa? Tell ar_spa.'  */
        case RT_H2N_U16_C(RTNET_ARPOP_REQUEST):
            if (pArp->ar_tpa.u != IPv4Addr.u)
                return true;
            Reply.Hdr.ar_oper = RT_H2N_U16_C(RTNET_ARPOP_REPLY);
            break;

        case RT_H2N_U16_C(RTNET_ARPOP_REVREQUEST):
            if (    pArp->ar_tha.au16[0] != pMacAddr->au16[0]
                ||  pArp->ar_tha.au16[1] != pMacAddr->au16[1]
                ||  pArp->ar_tha.au16[2] != pMacAddr->au16[2])
                return true;
            Reply.Hdr.ar_oper = RT_H2N_U16_C(RTNET_ARPOP_REVREPLY);
            break;

        case RT_H2N_U16_C(RTNET_ARPOP_INVREQUEST):
            /** @todo RTNET_ARPOP_INVREQUEST */
            return true;
            //Reply.Hdr.ar_oper = RT_H2N_U16_C(RTNET_ARPOP_INVREPLY);
            //break;
    }

    /*
     * Complete the reply and send it.
     */
    Reply.Hdr.ar_htype = RT_H2N_U16_C(RTNET_ARP_ETHER);
    Reply.Hdr.ar_ptype = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4);
    Reply.Hdr.ar_hlen  = sizeof(RTMAC);
    Reply.Hdr.ar_plen  = sizeof(RTNETADDRIPV4);
    Reply.ar_sha = *pMacAddr;
    Reply.ar_spa = IPv4Addr;
    Reply.ar_tha = pArp->ar_sha;
    Reply.ar_tpa = pArp->ar_spa;


    RTNETETHERHDR EthHdr;
    EthHdr.DstMac    = pArp->ar_sha;
    EthHdr.SrcMac    = *pMacAddr;
    EthHdr.EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_ARP);

    uint8_t abTrailer[60 - sizeof(Reply) - sizeof(EthHdr)];
    memset(abTrailer, '\0', sizeof(abTrailer));

    INTNETSEG aSegs[3];
    aSegs[0].cb = sizeof(EthHdr);
    aSegs[0].pv = &EthHdr;

    aSegs[1].pv = &Reply;
    aSegs[1].cb = sizeof(Reply);

    aSegs[2].pv = &abTrailer[0];
    aSegs[2].cb = sizeof(abTrailer);

    VBoxNetIntIfSend(pSession, hIf, pBuf, RT_ELEMENTS(aSegs), &aSegs[0], true /* fFlush */);

    return true;
}
Exemplo n.º 2
0
/** Internal worker for VBoxNetUDPUnicast and VBoxNetUDPBroadcast. */
static int vboxnetudpSend(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF pBuf,
                          RTNETADDRIPV4 SrcIPv4Addr, PCRTMAC pSrcMacAddr, unsigned uSrcPort,
                          RTNETADDRIPV4 DstIPv4Addr, PCRTMAC pDstMacAddr, unsigned uDstPort,
                          void const *pvData, size_t cbData)
{
    INTNETSEG aSegs[4];

    /* the Ethernet header */
    RTNETETHERHDR EtherHdr;
    EtherHdr.DstMac     = *pDstMacAddr;
    EtherHdr.SrcMac     = *pSrcMacAddr;
    EtherHdr.EtherType  = RT_H2BE_U16_C(RTNET_ETHERTYPE_IPV4);

    aSegs[0].pv   = &EtherHdr;
    aSegs[0].cb   = sizeof(EtherHdr);
    aSegs[0].Phys = NIL_RTHCPHYS;

    /* the IP header */
    RTNETIPV4 IpHdr;
    unsigned  cbIdHdr = RT_UOFFSETOF(RTNETIPV4, ip_options);
    IpHdr.ip_v          = 4;
    IpHdr.ip_hl         = cbIdHdr >> 2;
    IpHdr.ip_tos        = 0;
    IpHdr.ip_len        = RT_H2BE_U16((uint16_t)(cbData + sizeof(RTNETUDP) + cbIdHdr));
    IpHdr.ip_id         = (uint16_t)RTRandU32();
    IpHdr.ip_off        = 0;
    IpHdr.ip_ttl        = 255;
    IpHdr.ip_p          = RTNETIPV4_PROT_UDP;
    IpHdr.ip_sum        = 0;
    IpHdr.ip_src        = SrcIPv4Addr;
    IpHdr.ip_dst        = DstIPv4Addr;
    IpHdr.ip_sum        = RTNetIPv4HdrChecksum(&IpHdr);

    aSegs[1].pv   = &IpHdr;
    aSegs[1].cb   = cbIdHdr;
    aSegs[1].Phys = NIL_RTHCPHYS;


    /* the UDP bit */
    RTNETUDP UdpHdr;
    UdpHdr.uh_sport     = RT_H2BE_U16(uSrcPort);
    UdpHdr.uh_dport     = RT_H2BE_U16(uDstPort);
    UdpHdr.uh_ulen      = RT_H2BE_U16((uint16_t)(cbData + sizeof(RTNETUDP)));
#if 0
    UdpHdr.uh_sum       = 0; /* pretend checksumming is disabled */
#else
    UdpHdr.uh_sum       = RTNetIPv4UDPChecksum(&IpHdr, &UdpHdr, pvData);
#endif

    aSegs[2].pv   = &UdpHdr;
    aSegs[2].cb   = sizeof(UdpHdr);
    aSegs[2].Phys = NIL_RTHCPHYS;

    /* the payload */
    aSegs[3].pv   = (void *)pvData;
    aSegs[3].cb   = (uint32_t)cbData;
    aSegs[3].Phys = NIL_RTHCPHYS;


    /* send it */
    return VBoxNetIntIfSend(pSession, hIf, pBuf, RT_ELEMENTS(aSegs), &aSegs[0], true /* fFlush */);
}