third_party/virtualbox/src/VBox/Devices/Network/DevE1000.cpp
/**
 * Transmit complete frame.
 *
 * @remarks We skip the FCS since we're not responsible for sending anything to
 *          a real ethernet wire.
 *
 * @param   pThis              The device state structure.
 * @param   fOnWorkerThread     Whether we're on a worker thread or an EMT.
 * @thread  E1000_TX
 */
Transmit complete frame.
@remarks We skip the FCS since we're not responsible for sending anything to
a real ethernet wire.

@param   pThis              The device state structure.
@param   fOnWorkerThread     Whether we're on a worker thread or an EMT.
Transmit complete frame . @remarks We skip the FCS since we ' re not responsible for sending anything to a real ethernet wire . @param pThis The device state structure . @param fOnWorkerThread Whether we ' re on a worker thread or an EMT .
static void e1kTransmitFrame(PE1KSTATE pThis, bool fOnWorkerThread)
{
    PPDMSCATTERGATHER   pSg     = pThis->CTX_SUFF(pTxSg);
    uint32_t            cbFrame = pSg ? (uint32_t)pSg->cbUsed : 0;
    Assert(!pSg || pSg->cSegs == 1);
    if (cbFrame > 70) 
        pThis->led.Asserted.s.fWriting = pThis->led.Actual.s.fWriting = 1;
#ifdef E1K_INT_STATS
    if (cbFrame <= 1514)
        E1K_INC_ISTAT_CNT(pThis->uStatTx1514);
    else if (cbFrame <= 2962)
        E1K_INC_ISTAT_CNT(pThis->uStatTx2962);
    else if (cbFrame <= 4410)
        E1K_INC_ISTAT_CNT(pThis->uStatTx4410);
    else if (cbFrame <= 5858)
        E1K_INC_ISTAT_CNT(pThis->uStatTx5858);
    else if (cbFrame <= 7306)
        E1K_INC_ISTAT_CNT(pThis->uStatTx7306);
    else if (cbFrame <= 8754)
        E1K_INC_ISTAT_CNT(pThis->uStatTx8754);
    else if (cbFrame <= 16384)
        E1K_INC_ISTAT_CNT(pThis->uStatTx16384);
    else if (cbFrame <= 32768)
        E1K_INC_ISTAT_CNT(pThis->uStatTx32768);
    else
        E1K_INC_ISTAT_CNT(pThis->uStatTxLarge);
#endif 
    if (cbFrame > 12 && pThis->fVTag)
    {
        E1kLog3(("%s Inserting VLAN tag %08x\n",
            pThis->szPrf, RT_BE2H_U16(VET) | (RT_BE2H_U16(pThis->u16VTagTCI) << 16)));
        memmove((uint8_t*)pSg->aSegs[0].pvSeg + 16, (uint8_t*)pSg->aSegs[0].pvSeg + 12, cbFrame - 12);
        *((uint32_t*)pSg->aSegs[0].pvSeg + 3) = RT_BE2H_U16(VET) | (RT_BE2H_U16(pThis->u16VTagTCI) << 16);
        pSg->cbUsed += 4;
        cbFrame     += 4;
        Assert(pSg->cbUsed == cbFrame);
        Assert(pSg->cbUsed <= pSg->cbAvailable);
    }
    E1K_INC_CNT32(TPT);
    E1K_ADD_CNT64(TOTL, TOTH, cbFrame);
    E1K_INC_CNT32(GPTC);
    if (pSg && e1kIsBroadcast(pSg->aSegs[0].pvSeg))
        E1K_INC_CNT32(BPTC);
    else if (pSg && e1kIsMulticast(pSg->aSegs[0].pvSeg))
        E1K_INC_CNT32(MPTC);
    E1K_ADD_CNT64(GOTCL, GOTCH, cbFrame);
    if (pThis->CTX_SUFF(pDrv))
        STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, cbFrame);
    if (cbFrame == 64)
        E1K_INC_CNT32(PTC64);
    else if (cbFrame < 128)
        E1K_INC_CNT32(PTC127);
    else if (cbFrame < 256)
        E1K_INC_CNT32(PTC255);
    else if (cbFrame < 512)
        E1K_INC_CNT32(PTC511);
    else if (cbFrame < 1024)
        E1K_INC_CNT32(PTC1023);
    else
        E1K_INC_CNT32(PTC1522);
    E1K_INC_ISTAT_CNT(pThis->uStatTxFrm);
    int rc = VERR_NET_DOWN;
    if (pSg && pSg->pvAllocator != pThis)
    {
        e1kPacketDump(pThis, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Outgoing");
        pThis->CTX_SUFF(pTxSg) = NULL;
        PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
        if (pDrv)
        {
            STAM_PROFILE_START(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
            rc = pDrv->pfnSendBuf(pDrv, pSg, fOnWorkerThread);
            STAM_PROFILE_STOP(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
        }
    }
    else if (pSg)
    {
        Assert(pSg->aSegs[0].pvSeg == pThis->aTxPacketFallback);
        e1kPacketDump(pThis, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Loopback");
        if (GET_BITS(RCTL, LBM) == RCTL_LBM_TCVR)
        {
            E1KRXDST status;
            RT_ZERO(status);
            status.fPIF = true;
            e1kHandleRxPacket(pThis, pSg->aSegs[0].pvSeg, cbFrame, status);
            rc = VINF_SUCCESS;
        }
        e1kXmitFreeBuf(pThis);
    }
    else
        rc = VERR_NET_DOWN;
    if (RT_FAILURE(rc))
    {
        E1kLogRel(("E1000: ERROR! pfnSend returned %Rrc\n", rc));
    }
    pThis->led.Actual.s.fWriting = 0;
}
static void e1kTransmitFrame ( PE1KSTATE pThis , bool fOnWorkerThread ) { PPDMSCATTERGATHER pSg = pThis -> CTX_SUFF ( pTxSg ) ; uint32_t cbFrame = pSg ? ( uint32_t ) pSg -> cbUsed : 0 ; Assert ( ! pSg || pSg -> cSegs == 1 ) ; if ( cbFrame > 70 ) pThis -> led . Asserted . s . fWriting = pThis -> led . Actual . s . fWriting = 1 ; #ifdef E1K_INT_STATS if ( cbFrame <= 1514 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx1514 ) ; else if ( cbFrame <= 2962 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx2962 ) ; else if ( cbFrame <= 4410 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx4410 ) ; else if ( cbFrame <= 5858 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx5858 ) ; else if ( cbFrame <= 7306 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx7306 ) ; else if ( cbFrame <= 8754 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx8754 ) ; else if ( cbFrame <= 16384 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx16384 ) ; else if ( cbFrame <= 32768 ) E1K_INC_ISTAT_CNT ( pThis -> uStatTx32768 ) ; else E1K_INC_ISTAT_CNT ( pThis -> uStatTxLarge ) ; #endif if ( cbFrame > 12 && pThis -> fVTag ) { E1kLog3 ( ( " \n " , pThis -> szPrf , RT_BE2H_U16 ( VET ) | ( RT_BE2H_U16 ( pThis -> u16VTagTCI ) << 16 ) ) ) ; memmove ( ( uint8_t * ) pSg -> aSegs [ 0 ] . pvSeg + 16 , ( uint8_t * ) pSg -> aSegs [ 0 ] . pvSeg + 12 , cbFrame - 12 ) ; * ( ( uint32_t * ) pSg -> aSegs [ 0 ] . pvSeg + 3 ) = RT_BE2H_U16 ( VET ) | ( RT_BE2H_U16 ( pThis -> u16VTagTCI ) << 16 ) ; pSg -> cbUsed += 4 ; cbFrame += 4 ; Assert ( pSg -> cbUsed == cbFrame ) ; Assert ( pSg -> cbUsed <= pSg -> cbAvailable ) ; } E1K_INC_CNT32 ( TPT ) ; E1K_ADD_CNT64 ( TOTL , TOTH , cbFrame ) ; E1K_INC_CNT32 ( GPTC ) ; if ( pSg && e1kIsBroadcast ( pSg -> aSegs [ 0 ] . pvSeg ) ) E1K_INC_CNT32 ( BPTC ) ; else if ( pSg && e1kIsMulticast ( pSg -> aSegs [ 0 ] . pvSeg ) ) E1K_INC_CNT32 ( MPTC ) ; E1K_ADD_CNT64 ( GOTCL , GOTCH , cbFrame ) ; if ( pThis -> CTX_SUFF ( pDrv ) ) STAM_REL_COUNTER_ADD ( & pThis -> StatTransmitBytes , cbFrame ) ; if ( cbFrame == 64 ) E1K_INC_CNT32 ( PTC64 ) ; else if ( cbFrame < 128 ) E1K_INC_CNT32 ( PTC127 ) ; else if ( cbFrame < 256 ) E1K_INC_CNT32 ( PTC255 ) ; else if ( cbFrame < 512 ) E1K_INC_CNT32 ( PTC511 ) ; else if ( cbFrame < 1024 ) E1K_INC_CNT32 ( PTC1023 ) ; else E1K_INC_CNT32 ( PTC1522 ) ; E1K_INC_ISTAT_CNT ( pThis -> uStatTxFrm ) ; int rc = VERR_NET_DOWN ; if ( pSg && pSg -> pvAllocator != pThis ) { e1kPacketDump ( pThis , ( uint8_t const * ) pSg -> aSegs [ 0 ] . pvSeg , cbFrame , " " ) ; pThis -> CTX_SUFF ( pTxSg ) = NULL ; PPDMINETWORKUP pDrv = pThis -> CTX_SUFF ( pDrv ) ; if ( pDrv ) { STAM_PROFILE_START ( & pThis -> CTX_SUFF_Z ( StatTransmitSend ) , a ) ; rc = pDrv -> pfnSendBuf ( pDrv , pSg , fOnWorkerThread ) ; STAM_PROFILE_STOP ( & pThis -> CTX_SUFF_Z ( StatTransmitSend ) , a ) ; } } else if ( pSg ) { Assert ( pSg -> aSegs [ 0 ] . pvSeg == pThis -> aTxPacketFallback ) ; e1kPacketDump ( pThis , ( uint8_t const * ) pSg -> aSegs [ 0 ] . pvSeg , cbFrame , " " ) ; if ( GET_BITS ( RCTL , LBM ) == RCTL_LBM_TCVR ) { E1KRXDST status ; RT_ZERO ( status ) ; status . fPIF = true ; e1kHandleRxPacket ( pThis , pSg -> aSegs [ 0 ] . pvSeg , cbFrame , status ) ; rc = VINF_SUCCESS ; } e1kXmitFreeBuf ( pThis ) ; } else rc = VERR_NET_DOWN ; if ( RT_FAILURE ( rc ) ) { E1kLogRel ( ( " \n " , rc ) ) ; } pThis -> led . Actual . s . fWriting = 0 ; }
Transmit complete frame.
Transmit complete frame .
/* unqualified guess */ /* E1K_INT_STATS */ /* Add VLAN tag */ /*    E1kLog2(("%s < < < Outgoing packet. Dump follows: > > >\n"
            "%.*Rhxd\n"
            "%s < < < < < < < < < < < < <  End of dump > > > > > > > > > > > >\n",
            pThis->szPrf, cbFrame, pSg->aSegs[0].pvSeg, pThis->szPrf));*/ /* Update the stats */ /* Update octet transmit counter */ /*
     * Dump and send the packet.
     */ /* Release critical section to avoid deadlock in CanReceive */ //e1kCsLeave(pThis); //e1kCsEnter(pThis, RT_SRC_POS); /** @todo do we actually need to check that we're in loopback mode here? */ /** @todo handle VERR_NET_DOWN and VERR_NET_NO_BUFFER_SPACE. Signal error ? */