VirtualBox

Changeset 82775 in vbox for trunk/src/VBox/Devices/Network


Ignore:
Timestamp:
Jan 16, 2020 11:50:12 AM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
135728
Message:

Just checking in porting changes so far. Haven't tried building them yet. Build disabled by default in gate

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp

    r82681 r82775  
    6060#include "VBoxDD.h"
    6161
     62/*
     63 * GSO = Generic Segmentation Offload
     64 * TSO = TCP Segmentation Offload
     65 * UDP = UDP Fragmentation Offset
    6266
    6367/*********************************************************************************************************************************
     
    7074#define VIRTIONET_MAX_FRAME_SIZE               65535 + 18     /**< Max IP pkt size + Ethernet header with VLAN tag  */
    7175#define VIRTIONET_MAC_FILTER_LEN               32
    72 #define VIRTIONET_MAX_VID                      (1 << 12)
    73 
    74 #define INSTANCE(a_pVirtio)                 ((a_pVirtio)->szInstanceName)
     76#define VIRTIONET_MAX_VLAN_ID                  (1 << 12)
     77#define VIRTIONET_PREALLOCATE_RX_SEG_COUNT    32
     78
    7579#define QUEUE_NAME(a_pVirtio, a_idxQueue)   ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName)
    7680#define VIRTQNAME(qIdx) (pThis->aszVirtqNames[qIdx])
    7781#define CBVIRTQNAME(qIdx) RTStrNLen(VIRTQNAME(qIdx), sizeof(VIRTQNAME(qIdx)))
     82#define FEATURE_ENABLED(feature) (pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)
     83#define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature))
    7884
    7985/* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */
     
    8793
    8894#define LUN0    0
     95
     96
     97/*
     98 * Glossary of networking acronyms used in the following bit definitions:
     99 *
     100 * GSO = Generic Segmentation Offload
     101 * TSO = TCP Segmentation Offload
     102 * UFO = UDP Fragmentation Offload
     103 * ECN = Explicit Congestion Notification
     104 */
     105
    89106/** @name VirtIO 1.0 NET Host feature bits (See VirtIO 1.0 specification, Section 5.6.3)
    90107 * @{  */
     
    106123#define VIRTIONET_F_CTRL_RX              RT_BIT_64(18)         /**< Control channel RX mode + MAC addr filtering    */
    107124#define VIRTIONET_F_CTRL_VLAN            RT_BIT_64(19)         /**< Control channel VLAN filtering                  */
     125#define VIRTIONET_F_CTRL_RX_EXTRA        RT_BIT_64(20)         /**< Control channel RX mode extra functions         */
    108126#define VIRTIONET_F_GUEST_ANNOUNCE       RT_BIT_64(21)         /**< Driver can send gratuitous packets              */
    109127#define VIRTIONET_F_MQ                   RT_BIT_64(22)         /**< Support ultiqueue with auto receive steering    */
     
    179197    uint16_t uHdrLen;                                          /**< hdr_len                                         */
    180198    uint16_t uGsoSize;                                         /**< gso_size                                        */
    181     uint16_t uCsumStart;                                       /**< csum_start                                      */
    182     uint16_t uCsumOffset;                                      /**< csum_offset                                     */
     199    uint16_t uChksumStart;                                     /**< Chksum_start                                      */
     200    uint16_t uChksumOffset;                                    /**< Chksum_offset                                     */
    183201    uint16_t uNumBuffers;                                      /**< num_buffers                                     */
    184202};
    185203#pragma pack()
    186 typedef virtio_net_hdr VIRTIONET_PKT_HDR, *PVIRTIONET_PKT_HDR;
    187 AssertCompileSize(VIRTIONET_PKT_HDR, 12);
     204typedef virtio_net_hdr VIRTIONET_PKT_HDR_T, *PVIRTIONET_PKT_HDR_T;
     205AssertCompileSize(VIRTIONET_PKT_HDR_T, 12);
    188206
    189207/* Control virtq: Command entry (VirtIO 1.0, 5.1.6.5) */
     
    192210    uint8_t uClass;                                             /**< class                                          */
    193211    uint8_t uCmd;                                               /**< command                                        */
     212    uint8_t uCmdSpecific;                                       /**< command specific                               */
    194213};
    195214#pragma pack()
    196 typedef virtio_net_ctrl_hdr VIRTIONET_CTRL_HDR, *PVIRTIONET_CTRL_HDR;
    197 
    198 typedef uint8_t VIRTIONET_CTRL_HDR_ACK;
     215typedef virtio_net_ctrl_hdr VIRTIONET_CTRL_HDR_T, *PVIRTIONET_CTRL_HDR_T;
     216
     217typedef uint8_t VIRTIONET_CTRL_HDR_T_ACK;
    199218
    200219/* Command entry fAck values */
    201 #define VIRTIO_NET_OK                               0
    202 #define VIRTIO_NET_ERR                              1
     220#define VIRTIONET_OK                               0
     221#define VIRTIONET_ERROR                            1
    203222
    204223/** @name Control virtq: Receive filtering flags (VirtIO 1.0, 5.1.6.5.1)
     
    213232/** @} */
    214233
    215 
    216 typedef uint32_t VIRTIONET_CTRL_MAC_HDR;
     234typedef uint8_t  VIRTIONET_MAC_ADDRESS[6];
     235typedef uint32_t VIRTIONET_CTRL_MAC_TABLE_LEN;
    217236typedef uint8_t  VIRTIONET_CTRL_MAC_ENTRIES[][6];
    218237
     
    253272/** @name Offload State Configuration Flags (VirtIO 1.0, 5.1.6.5.6.1)
    254273 * @{  */
    255 //#define VIRTIONET_F_GUEST_CSUM                      1           /**< Guest offloads CSUM                             */
     274//#define VIRTIONET_F_GUEST_CSUM                      1           /**< Guest offloads Chksum                             */
    256275//#define VIRTIONET_F_GUEST_TSO4                      7           /**< Guest offloads TSO4                             */
    257276//#define VIRTIONET_F_GUEST_TSO6                      8           /**< Guest Offloads TSO6                             */
     
    323342    /** Transmit Delay Timer. */
    324343    TMTIMERHANDLE           hTxTimer;
    325     uint32_t                u32i;
    326     uint32_t                u32AvgDiff;
    327     uint32_t                u32MinDiff;
    328     uint32_t                u32MaxDiff;
     344    uint32_t                ui;
     345    uint32_t                uAvgDiff;
     346    uint32_t                uMinDiff;
     347    uint32_t                uMaxDiff;
    329348    uint64_t                u64NanoTS;
    330349#else  /* !VNET_TX_DELAY */
     
    336355    uint32_t                uIsTransmitting;
    337356
    338 //    /** PCI config area holding MAC address as well as TBD. */
    339 //    struct VNetPCIConfig    config;
    340 
    341357    /** MAC address obtained from the configuration. */
    342358    RTMAC                   macConfigured;
    343359
     360    /** Default MAC address which rx filtering accepts */
     361    RTMAC                   rxFilterMacDefault;
     362
    344363    /** True if physical cable is attached in configuration. */
    345364    bool                    fCableConnected;
     
    351370
    352371    /** Number of packet being sent/received to show in debug log. */
    353     uint32_t                u32PktNo;
     372    uint32_t                uPktNo;
    354373
    355374    /** N/A: */
    356375    bool volatile           fMaybeOutOfSpace;
    357376
     377    /** Flags whether VirtIO core is in ready state */
     378    uint8_t                 fVirtioReady;
     379
    358380    /** Resetting flag */
    359     bool                    fResetting;
     381    uint8_t                 fResetting;
    360382
    361383    /** Promiscuous mode -- RX filter accepts all packets. */
    362     bool                    fPromiscuous;
    363     /** AllMulti mode -- RX filter accepts all multicast packets. */
    364     bool                    fAllMulti;
    365     /** The number of actually used slots in aMacTable. */
    366     uint32_t                cMacFilterEntries;
    367     /** Array of MAC addresses accepted by RX filter. */
    368     RTMAC                   aMacFilter[VIRTIONET_MAC_FILTER_LEN];
     384    uint8_t                 fPromiscuous;
     385
     386    /** All multicast mode -- RX filter accepts all multicast packets. */
     387    uint8_t                 fAllMulticast;
     388
     389    /** All unicast mode -- RX filter accepts all unicast packets. */
     390    uint8_t                 fAllUnicast;
     391
     392    /** No multicast mode - Supresses multicast receive */
     393    uint8_t                 fNoMulticat;
     394
     395    /** No unicast mode - Suppresses unicast receive */
     396    uint8_t                 fNoUnicast;
     397
     398    /** No broadcast mode - Supresses broadcast receive */
     399    uint8_t                 fNoBroadcast;
     400
     401    /** The number of actually used slots in aMacMulticastFilter. */
     402    uint32_t                cMulticastFilterMacs;
     403
     404    /** Array of MAC multicast addresses accepted by RX filter. */
     405    RTMAC                   aMacMulticastFilter[VIRTIONET_MAC_FILTER_LEN];
     406
     407    /** The number of actually used slots in aMacUniicastFilter. */
     408    uint32_t                cUnicastFilterMacs;
     409
     410    /** Array of MAC unicast addresses accepted by RX filter. */
     411    RTMAC                   aMacUnicastFilter[VIRTIONET_MAC_FILTER_LEN];
     412
    369413    /** Bit array of VLAN filter, one bit per VLAN ID. */
    370414    uint8_t                 aVlanFilter[VIRTIONET_MAX_VID / sizeof(uint8_t)];
     
    385429    STAMCOUNTER             StatTransmitPackets;
    386430    STAMCOUNTER             StatTransmitGSO;
    387     STAMCOUNTER             StatTransmitCSum;
     431    STAMCOUNTER             StatTransmitChksum;
    388432#ifdef VBOX_WITH_STATISTICS
    389433    STAMPROFILE             StatReceive;
     
    554598DECLINLINE(bool) virtioNetValidateRequiredFeatures(uint32_t fFeatures)
    555599{
    556     uint32_t fGuestCsumRequired = fFeatures & VIRTIONET_F_GUEST_TSO4
     600    uint32_t fGuestChksumRequired = fFeatures & VIRTIONET_F_GUEST_TSO4
    557601                               || fFeatures & VIRTIONET_F_GUEST_TSO6
    558602                               || fFeatures & VIRTIONET_F_GUEST_UFO;
    559603
    560     uint32_t fHostCsumRequired =  fFeatures & VIRTIONET_F_HOST_TSO4
     604    uint32_t fHostChksumRequired =  fFeatures & VIRTIONET_F_HOST_TSO4
    561605                               || fFeatures & VIRTIONET_F_HOST_TSO6
    562606                               || fFeatures & VIRTIONET_F_HOST_UFO;
     
    568612                               || fFeatures & VIRTIONET_F_CTRL_MAC_ADDR;
    569613
    570     if (fGuestCsumRequired && !(fFeatures & VIRTIONET_F_GUEST_CSUM))
     614    if (fGuestChksumRequired && !(fFeatures & VIRTIONET_F_GUEST_CSUM))
    571615        return false;
    572616
    573     if (fHostCsumRequired && !(fFeatures & VIRTIONET_F_CSUM))
     617    if (fHostChksumRequired && !(fFeatures & VIRTIONET_F_CSUM))
    574618        return false;
    575619
     
    616660        }
    617661    }
    618 }
    619 
    620 /**
    621  * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged}
    622  */
    623 static DECLCALLBACK(void) virtioNetR3StatusChanged(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
    624 {
    625     PVIRTIONET     pThis     = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio);
    626     PVIRTIONETCC   pThisCC   = RT_FROM_MEMBER(pVirtioCC, VIRTIONETCC, Virtio);
    627 
    628     RT_NOREF5(pThis, pThisCC, pVirtio, pVirtioCC, fVirtioReady);
    629662}
    630663
     
    766799    PVIRTIONET     pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    767800    PVIRTIONETCC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    768     PCPDMDEVHLPR3   pHlp    = pDevIns->pHlpR3;
     801    PCPDMDEVHLPR3  pHlp    = pDevIns->pHlpR3;
    769802
    770803    RT_NOREF(pThisCC);
     
    778811    for (int qIdx = 0; qIdx < pThis->cVirtQueues; qIdx++)
    779812        pHlp->pfnSSMGetBool(pSSM, &pThis->afQueueAttached[qIdx]);
    780 
    781813
    782814    /*
     
    835867    PVIRTIONETCC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    836868
    837 //    if (ASMAtomicReadU32(&pThis->cActiveReqs))
     869//    if (ASMAtomicReadu(&pThis->cActiveReqs))
    838870//        return false;
    839871
     
    866898
    867899    /* If already quiesced invoke async callback.  */
    868 //    if (!ASMAtomicReadU32(&pThis->cActiveReqs))
     900//    if (!ASMAtomicReadu(&pThis->cActiveReqs))
    869901//        PDMDevHlpAsyncNotificationCompleted(pDevIns);
    870902}
     
    951983}
    952984
    953 static void virtioNetR3Ctrl(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, PVIRTIO_DESC_CHAIN_T pDescChain)
    954 {
    955     RT_NOREF4(pDevIns, pThis, pThisCC, pDescChain);
    956 }
     985/* Device operation: Net header packet (VirtIO 1.0, 5.1.6) */
     986#pragma pack(1)
     987struct virtio_net_hdr {
     988    uint8_t  uFlags;                                           /**< flags                                           */
     989    uint8_t  uGsoType;                                         /**< gso_type                                        */
     990    uint16_t uHdrLen;                                          /**< hdr_len                                         */
     991    uint16_t uGsoSize;                                         /**< gso_size                                        */
     992    uint16_t uChksumStart;                                     /**< csum_start                                      */
     993    uint16_t uChksumOffset;                                    /**< csum_offset                                     */
     994    uint16_t uNumBuffers;                                      /**< num_buffers                                     */
     995};
     996#pragma pack()
     997typedef virtio_net_hdr VIRTIONET_PKT_HDR_T, *PVIRTIONET_PKT_HDR_T;
     998AssertCompileSize(VIRTIONET_PKT_HDR_T, 12);
     999
     1000/**
     1001 * Determines if the packet is to be delivered to upper layer.
     1002 *
     1003 * @returns true if packet is intended for this node.
     1004 * @param   pThis          Pointer to the state structure.
     1005 * @param   pvBuf           The ethernet packet.
     1006 * @param   cb              Number of bytes available in the packet.
     1007 */
     1008static bool vnetR3AddressFilter(PVNETSTATE pThis, const void *pvBuf, size_t cb)
     1009{
     1010    if (pThis->fPromiscuous)
     1011        return true;
     1012
     1013    /* Ignore everything outside of our VLANs */
     1014    uint16_t *uPtr = (uint16_t*)pvBuf;
     1015    /* Compare TPID with VLAN Ether Type */
     1016    if (   uPtr[6] == RT_H2BE_u(0x8100)
     1017        && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_u(uPtr[7]) & 0xFFF))
     1018    {
     1019        Log4(("%s vnetR3AddressFilter: not our VLAN, returning false\n", INSTANCE(pThis)));
     1020        return false;
     1021    }
     1022
     1023    if (vnetR3IsBroadcast(pvBuf))
     1024        return true;
     1025
     1026    if (pThis->fAllMulti && vnetR3IsMulticast(pvBuf))
     1027        return true;
     1028
     1029    if (!memcmp(pThis->config.mac.au, pvBuf, sizeof(RTMAC)))
     1030        return true;
     1031    Log4(("%s vnetR3AddressFilter: %RTmac (conf) != %RTmac (dest)\n", INSTANCE(pThis), pThis->config.mac.au, pvBuf));
     1032
     1033    for (unsigned i = 0; i < pThis->cMacFilterEntries; i++)
     1034        if (!memcmp(&pThis->aMacFilter[i], pvBuf, sizeof(RTMAC)))
     1035            return true;
     1036
     1037    Log2(("%s vnetR3AddressFilter: failed all tests, returning false, packet dump follows:\n", INSTANCE(pThis)));
     1038    vnetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     1039
     1040    return false;
     1041}
     1042
     1043/**
     1044 * Pad and store received packet.
     1045 *
     1046 * @remarks Make sure that the packet appears to upper layer as one coming
     1047 *          from real Ethernet: pad it and insert FCS.
     1048 *
     1049 * @returns VBox status code.
     1050 * @param   pDevIns         The device instance.
     1051 * @param   pThis           The virtio-net shared instance data.
     1052 * @param   pvBuf           The available data.
     1053 * @param   cb              Number of bytes available in the buffer.
     1054 * @thread  RX
     1055 */
     1056static int virtioNetR3HandleRxPacket(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     1057                                const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso)
     1058{
     1059    VIRTIONET_PKT_HDR_T rxPktHdr;
     1060
     1061    if (pGso)
     1062    {
     1063        Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
     1064              pThis->szInstanceName, pGso->uType, pGso->cbHdrsTotal,
     1065              pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
     1066
     1067        rxPktHdr.uFlags = VIRTIONET_HDR_F_NEEDS_CSUM;
     1068        switch (pGso->uType)
     1069        {
     1070            case PDMNETWORKGSOTYPE_IPV4_TCP:
     1071                rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_TCPV4;
     1072                rxPktHdr.uCSumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
     1073                break;
     1074            case PDMNETWORKGSOTYPE_IPV6_TCP:
     1075                rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_TCPV6;
     1076                rxPktHdr.uCSumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
     1077                break;
     1078            case PDMNETWORKGSOTYPE_IPV4_UDP:
     1079                rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_UDP;
     1080                rxPktHdr.uCSumOffset = RT_OFFSETOF(RTNETUDP, uh_sum);
     1081                break;
     1082            default:
     1083                return VERR_INVALID_PARAMETER;
     1084        }
     1085        rxPktHdr.uHdrLen = pGso->cbHdrsTotal;
     1086        rxPktHdr.uGSOSize = pGso->cbMaxSeg;
     1087        rxPktHdr.uCSumStart = pGso->offHdr2;
     1088        STAM_REL_COUNTER_INC(&pThis->StatReceiveGSO);
     1089    }
     1090    else
     1091    {
     1092        rxPktHdr.uFlags = 0;
     1093        rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_NONE;
     1094    }
     1095
     1096    virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     1097
     1098    PRTSGBUF pSegsBuf;
     1099    PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2);
     1100    AssertReturn(paSegs, VERR_NO_MEMORY);
     1101    RTSgBufInit(pSegsBuf, paSegs, cSegs);
     1102
     1103    uint16_t *pPhysPktHdrNumBufs, cDescs = 0;
     1104
     1105    uint8_t fFirstIteration = true;
     1106    for (uint32_t uOffset = 0; uOffset < cb; fFirstIteration = false)
     1107    {
     1108        PVIRTIO_DESC_CHAIN_T pDescChain;
     1109        int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX(0), &pDescChain, true);
     1110
     1111        AssertRC(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, rc);
     1112
     1113        /* todo:  Find a better way to deal with this */
     1114        AssertMsgReturn(rc == VINF_SUCCESS && pDescChain->cbPhysSend,
     1115                        ("Not enough Rx buffers in queue to accomodate ethernet packet\n"),
     1116                        VERR_INTERNAL_ERROR);
     1117
     1118        AssertMsgReturn(pDescChain->cbPhysReturn >= sizeof(VIRTIONET_PKT_HDR_T),
     1119                        ("Desc chain's phys segs have insufficient space for pkt header!\n"),
     1120                        VERR_INTERNAL_ERROR);
     1121
     1122        uint32_t cbDescChainLeft = pDescChain->cbPhysSend;
     1123
     1124        uint16_t cSegs = 0;
     1125        if (fFirstIteration)
     1126        {
     1127            /* Lead with packet header */
     1128            paSegs[cSegs].cbSeg = sizeof(VIRTIONET_PKT_HDR_T);
     1129            paSegs[cSegs].pvSeg = RTMemAlloc(paSegs[0].cb);
     1130            AssertReturn(paSegs[0].pvSeg, VERR_NO_MEMORY);
     1131            cbDescChainLeft -= paReqSegs[0].cb;
     1132            *pPhysPktHdrNumBufs = ((uint8_t *)paSegs[cSegs].pvSeg)
     1133                                     + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers);
     1134            cSegs++;
     1135        }
     1136
     1137        /* Append remaining Rx pkt or as much current desc chain has room for */
     1138        uint32_t uSize = RT_MIN(cb, cbDescChainLeft);
     1139        paSegs[cSegs].cbSeg = uSize;
     1140        paSegs[cSegs++].pvSeg = ((uint8_t)pvBuf) + uOffset;
     1141        uOffset += uSize;
     1142        cDescs++;
     1143
     1144        virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, RXQIDX(0), pSegsBuf, pDescChain, true);
     1145
     1146        if (FEATURE_DISABLED(MRG_RXBUF))
     1147            break;
     1148    }
     1149
     1150    /* Fix up pkt hdr (already in guest phys. memory) with number of descriptors to send */
     1151
     1152    int rc = PDMDevHlpPCIPhysWrite(pDevIns, pPhysPktHdrNumBuffers, cDescs, sizeof(cDescs));
     1153    AssertMsgRCReturn(rc, "Failure updating descriptor count in pkt hdr in guest physical memory\n");
     1154
     1155    virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX(0));
     1156
     1157    for (int i = 0; i < 2; i++)
     1158        RTMemFree(paSegs[i].pvSeg);
     1159    RTMemFree(paSegs);
     1160    RTMemFree(pSegsBuf);
     1161
     1162    if (uOffset < cb)
     1163    {
     1164        Log(("%s vnetR3HandleRxPacket: Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb));
     1165        return VERR_TOO_MUCH_DATA;
     1166    }
     1167
     1168    return VINF_SUCCESS;
     1169}
     1170
     1171/**
     1172 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso}
     1173 */
     1174static DECLCALLBACK(int) virtioNetR3ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf,
     1175                                               size_t cb, PCPDMNETWORKGSO pGso)
     1176{
     1177    PVIRTIONETCC    pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkDown);
     1178    PPDMDEVINS      pDevIns = pThisCC->pDevIns;
     1179    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     1180
     1181    if (pGso)
     1182    {
     1183        uint32_t uFeatures = pThis->VPCI.uGuestFeatures;
     1184
     1185        switch (pGso->uType)
     1186        {
     1187            case PDMNETWORKGSOTYPE_IPV4_TCP:
     1188                uFeatures &= VIRTIONET_F_GUEST_TSO4;
     1189                break;
     1190            case PDMNETWORKGSOTYPE_IPV6_TCP:
     1191                uFeatures &= VIRTIONET_F_GUEST_TSO6;
     1192                break;
     1193            case PDMNETWORKGSOTYPE_IPV4_UDP:
     1194            case PDMNETWORKGSOTYPE_IPV6_UDP:
     1195                uFeatures &= VIRTIONET_F_GUEST_UFO;
     1196                break;
     1197            default:
     1198                uFeatures = 0;
     1199                break;
     1200        }
     1201        if (!uFeatures)
     1202        {
     1203            Log2Func((GSO type (0x%x) not supported\n", pThis->szInstanceName, pGso->uType));
     1204            return VERR_NOT_SUPPORTED;
     1205        }
     1206    }
     1207
     1208    Log2Func(("pvBuf=%p cb=%u pGso=%p\n", pThis->szInstanceName, pvBuf, cb, pGso));
     1209
     1210    int rc = virtioR3CanReceive(pDevIns, pThis, pThisCC);
     1211    if (RT_FAILURE(rc))
     1212        return rc;
     1213
     1214    /* Drop packets if VM is not running or cable is disconnected. */
     1215    VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
     1216    if ((   enmVMState != VMSTATE_RUNNING
     1217         && enmVMState != VMSTATE_RUNNING_LS)
     1218        || !(pThis->virtioNetConfig.uStatus & VIRTIONET_S_LINK_UP))
     1219        return VINF_SUCCESS;
     1220
     1221    STAM_PROFILE_START(&pThis->StatReceive, a);
     1222    virtioNetR3SetReadLed(&pThisCC, true);
     1223    if (virtioNetR3AddressFilter(pThis, pvBuf, cb))
     1224    {
     1225        rc = virtioNetCsRxEnter(pThis, VERR_SEM_BUSY);
     1226        if (RT_SUCCESS(rc))
     1227        {
     1228            rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso);
     1229            STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb);
     1230            virtioNetCsRxLeave(pThis);
     1231        }
     1232    }
     1233    virtioNetR3SetReadLed(&pThisCC, false);
     1234    STAM_PROFILE_STOP(&pThis->StatReceive, a);
     1235    return rc;
     1236}
     1237
     1238
     1239DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb)
     1240{
     1241    uint32_t  chksum = 0;
     1242    uint16_t *pu = (uint16_t *)pvBuf;
     1243
     1244    while (cb > 1)
     1245    {
     1246        chksum += *pu++;
     1247        cb -= 2;
     1248    }
     1249    if (cb)
     1250        chksum += *(uint8_t*)pu;
     1251    while (chksum >> 16)
     1252        chksum = (chksum >> 16) + (chksum & 0xFFFF);
     1253    return ~chksum;
     1254}
     1255
     1256DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset)
     1257{
     1258    AssertReturnVoid(uStart < cbSize);
     1259    AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize);
     1260    *(uint16_t *)(pBuf + uStart + uOffset) = vnetR3Chksum16(pBuf + uStart, cbSize - uStart);
     1261}
     1262
     1263/* Read physical bytes from the out segment(s) of descriptor chain */
     1264static void virtioNetR3PullChain(PVIRTIO_DESC_CHAIN_T pDecChain, void *pv, uint16_t cb)
     1265{
     1266    uint8_t *pb = (uint8_t *)pv;
     1267    for (size_t cb = RT_MIN(pDescChain->cbPhysSend, sizeof(VIRTIONET_PKT_HDR_T)); cb; )
     1268    {
     1269        size_t cbSeg = cb;
     1270        RTGCPHYS GCPhys = virtioCoreSgBufGetNextSegment(pDescChain->pSgPhysSend, &cbSeg);
     1271        PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pb, cbSeg);
     1272        pb += cbSeg;
     1273        cb -= cbSeg;
     1274    }
     1275}
     1276static bool virtioNetR3ReadHeader(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONET_PKT_HDR_T pPktHdr, uint32_t cbMax)
     1277{
     1278    int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pPktHdr, sizeof(*pPktHdr));
     1279    if (RT_FAILURE(rc))
     1280        return false;
     1281
     1282    Log4(("virtio-net: header flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x cb=%x\n",
     1283          pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, pPktHdr->uGSOSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax));
     1284
     1285    if (pPktHdr->uGsoType)
     1286    {
     1287        uint32_t uMinHdrSize;
     1288
     1289        /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */
     1290        if (  RT_UNLIKELY(!(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM))
     1291            | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN)))
     1292                return false;
     1293
     1294        switch (pPktHdr->uGsoType)
     1295        {
     1296            case VIRTIONET_HDR_GSO_TCPV4:
     1297            case VIRTIONET_HDR_GSO_TCPV6:
     1298                uMinHdrSize = sizeof(RTNETTCP);
     1299                break;
     1300            case VIRTIONET_HDR_GSO_UDP:
     1301                uMinHdrSize = 0;
     1302                break;
     1303            default:
     1304                return false;
     1305        }
     1306        /* Header + MSS must not exceed the packet size. */
     1307        if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGSOSize > cbMax))
     1308            return false;
     1309    }
     1310    /* Checksum must fit into the frame (validating both checksum fields). */
     1311    if ((   pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)
     1312         && sizeof(uint16_t) + pPktHdr->uChksumStart + pPktHdr->uChksumOffset > cbMax)
     1313               return false;
     1314    Log4func(("returning true\n"));
     1315    return true;
     1316}
     1317
     1318static uint8_t virtioNetR3CtrlRx(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     1319                                 PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
     1320{
     1321#define LOG_VIRTIONET_FLAG(field) LogFunc(("%s = %d\n", #field, pThis->field));
     1322
     1323    LogFunc((""));
     1324    switch(pCtrlPktHdr->uCmd)
     1325    {
     1326      case VIRTIONET_CTRL_RX_PROMISC:
     1327        break;
     1328      case VIRTIONET_CTRL_RX_ALLMULTI:
     1329        break;
     1330      case VIRTIONET_CTRL_RX_ALLUNI:
     1331        /* fallthrough */
     1332      case VIRTIONET_CTRL_RX_NOMULTI:
     1333        /* fallthrough */
     1334      case VIRTIONET_CTRL_RX_NOUNI:
     1335        /* fallthrough */
     1336      case VIRTIONET_CTRL_RX_NOBCAST:
     1337        AssertMsgReturn(fFeatures & VIRTIONET_F_CTRL_RX_EXTRA,
     1338                        ("CTRL "extra" cmd w/o VIRTIONET_F_CTRL_RX_EXTRA feature negotiated - skipping\n"),
     1339                        VIRTIONET_ERROR);
     1340        /* fall out */
     1341    }
     1342
     1343    uint8_t fOn, fPromiscChanged = false;
     1344    virtioNetR3PullChain(pDescChain, &fOn, RT_MIN(pDescChain->cbPhysSend, sizeof(fOn)));
     1345
     1346    switch(pCtrlPktHdr->uCmd)
     1347    {
     1348      case VIRTIONET_CTRL_RX_PROMISC:
     1349        pThis->fPromiscuous = !!fOn;
     1350        fPromiscChanged = true;
     1351        LOG_VIRTIONET_FLAG(fPromiscuous)
     1352        break;
     1353      case VIRTIONET_CTRL_RX_ALLMULTI:
     1354        pThis->fAllMulticast = !!fOn;
     1355        fPromiscChanged = true;
     1356        LOG_VIRTIONET_FLAG(fAllMulticast);
     1357        break;
     1358      case VIRTIONET_CTRL_RX_ALLUNI:
     1359        pThis->fAllUnicast = !!fOn;
     1360        LOG_VIRTIONET_FLAG(fAllUnicast);
     1361        break;
     1362      case VIRTIONET_CTRL_RX_NOMULTI:
     1363        pThis->fNoMulticast = !!fOn;
     1364        LOG_VIRTIONET_FLAG(fNoMulticast);
     1365        break;
     1366      case VIRTIONET_CTRL_RX_NOUNI:
     1367        pThis->fNoUnicast = !!fOn;
     1368        LOG_VIRTIONET_FLAG(fNoUnicast);
     1369        break;
     1370      case VIRTIONET_CTRL_RX_NOBCAST:
     1371        pThis->fNoBroadcast = !!fOn;
     1372        LOG_VIRTIONET_FLAG(fNoBroadcast);
     1373        break;
     1374    }
     1375
     1376    if (pThisCC->pDrv && fPromiscChanged)
     1377    {
     1378        uint8_t fPromiscuous = pThis->fPromiscuous | pThis->fAllMulticast
     1379        LogFunc(("Setting promiscuous state to %d\n", fPromiscuous));
     1380        pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, fPromiscuous);
     1381    }
     1382
     1383    return VIRTIONET_OK;
     1384}
     1385
     1386static uint8_t virtioNetR3CtrlMac(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     1387                                  PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
     1388{
     1389#define ASSERT_CTRL_ADDR_SET(v) \
     1390    AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd"), VIRTIONET_ERROR);
     1391
     1392#define ASSERT_CTRL_TABLE_SET(v) \
     1393    AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd"), VIRTIONET_ERROR);
     1394
     1395    int cbRemaining = pDescChain.cbPhysSend - sizeof(*pCtrlPktHdr);
     1396
     1397    switch(pCtrlPktHder->uCmd)
     1398    {
     1399        case VIRTIONET_CTRL_MAC_ADDR_SET:
     1400        {
     1401            /* Set default Rx filter MAC */
     1402            ASSERT_CTRL_ADDR_SET(cbRemaining >= sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));
     1403            virtioNetR3PullChain(pDescChain, &pThis->rxFilterMacDefault, sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));
     1404            break;
     1405        }
     1406        case VIRTIONET_CTRL_MAC_TABLE_SET:
     1407        {
     1408            VIRTIONET_CTRL_MAC_TABLE_LEN cMacs;
     1409
     1410            /* Load unicast MAC filter table */
     1411            ASSERT_CTRL_TABLE_SET(cbRemaining >= sizeof(cMacs));
     1412            virtioNetR3PullChain(pDescChain, &cMacs, sizeof(cMacs));
     1413            cbRemaining -= sizeof(cMacs);
     1414            uint32_t cbMacs = cMacs * sizeof(RTMAC);
     1415            ASSERT_CTRL_TABLE_SET(cbRemaining >= cbMacs);
     1416            virtioNetR3PullChain(pDescChain, &pThis->aMacUnicastFilter, cbMacs);
     1417            cbRemaining -= cbMacs;
     1418            pThis->cUnicastFilterMacs = cMacs;
     1419
     1420            /* Load multicast MAC filter table */
     1421            ASSERT_CTRL_TABLE_SET(cbRemaining >= sizeof(cMacs));
     1422            virtioNetR3PullChain(pDescChain, &cMacs, sizeof(cMacs));
     1423            cbRemaining -= sizeof(cMacs);
     1424            cbMacs = cMacs * sizeof(RTMAC);
     1425            ASSERT_CTRL_TABLE_SET(cbRemaining >= cbMacs);
     1426            virtioNetR3PullChain(pDescChain, &pThis->aMacMulticastFilter, cbMacs);
     1427            cbRemaining -= cbMacs;
     1428            pThis->cMulticastFilterMacs = cMacs;
     1429
     1430#ifdef LOG_ENABLED
     1431            LogFunc(("%s: unicast MACs:\n", pThis->szInstanceName)));
     1432            for(unsigned i = 0; i < nMacs; i++)
     1433                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
     1434
     1435            LogFunc(("%s: multicast MACs:\n", pThis->szInstanceName)));
     1436            for(unsigned i = 0; i < nMacs; i++)
     1437                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
     1438#endif
     1439
     1440        }
     1441    }
     1442    return VIRTIONET_OK;
     1443}
     1444
     1445static uint8_t virtioNetR3CtrlVlan(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     1446                                   PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
     1447{
     1448    uint16_t uVlanId;
     1449    int cbRemaining = pDescChain.cbPhysSend - sizeof(*pCtrlPktHdr);
     1450    AssertMsgReturn(cbRemaining > sizeof(uVlanId),
     1451        ("DESC chain too small for VIRTIO_NET_CTRL_VLAN cmd processing"), VIRTIONET_ERROR);
     1452    virtioNetR3PullChain(pDescChain, &uVlanId, sizeof(uVlanId));
     1453    AssertMsgReturn(uVlanId > VIRTIONET_MAX_VLAN_ID,
     1454        ("%s VLAN ID out of range (VLAN ID=%u)\n", pThis->szInstanceName, uVlanId), VIRTIONET_ERROR);
     1455    LogFunc(("%s: uCommand=%u VLAN ID=%u\n", pThis->szInstanceName, pCtrlPktHdr->uCmd, uVlanId));
     1456    switch (pCtrlPktHdr->uCmd)
     1457    {
     1458        case VIRTIONET_CTRL_VLAN_ADD:
     1459            ASMBitSet(pThis->aVlanFilter, uVlanId);
     1460            break;
     1461        case VIRTIONET_CTRL_VLAN_DEL:
     1462            ASMBitClear(pThis->aVlanFilter, uVlanId);
     1463            break;
     1464        default:
     1465            return VIRTIONET_ERROR;
     1466    }
     1467    return VIRTIONET_OK;
     1468}
     1469
     1470static void virtioNetR3Ctrl(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     1471                            PVIRTIO_DESC_CHAIN_T pDescChain)
     1472{
     1473    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     1474    PVIRTIONETCC    pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
     1475
     1476
     1477    if (pDescChain->cbPhysSend < 2)
     1478    {
     1479        LogFunc(("ctrl packet from guest driver incomplete. Skipping ctrl cmd\n"));
     1480        return;
     1481    }
     1482    else if (pDescChain->cbPhysReturn < sizeof(VIRTIONET_CTRL_HDR_T_ACK))
     1483    {
     1484        LogFunc(("Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n"));
     1485        return;
     1486    }
     1487
     1488    /*
     1489     * Allocate buffer and read in the control command
     1490     */
     1491    PVIRTIONET_PKT_HDR_T pCtrlPktHdr = (PVIRTIONET_PKT_HDR_T)RTMemAllocZ(sizeof(VIRTIONET_PKT_HDR_T));
     1492    AssertPtrReturn(pCtrlPktHdr, VERR_NO_MEMORY /*ignored*/);
     1493
     1494    AssertMsgReturnVoid(pDescChain >= sizeof(*pCtrlPktHdr), ("DESC chain too small for CTRL pkt header"));
     1495    virtioNetR3PullChain(pDescChain, pCtrlPktHdr, SIZEOF_SEND(pDescChain, VIRTIONET_PKT_HDR_T));
     1496
     1497    uint8_t uAck;
     1498    switch (pCtrlPktHdr->uClass)
     1499    {
     1500        case VIRTIONET_CTRL_RX:
     1501            uAck = virtioNetR3CtrlRx(pDevIns, pThis, pThisCC, pCtrlPktHdr, pDescChain);
     1502            break;
     1503        case VIRTIONET_CTRL_MAC:
     1504            uAck = virtioNetR3CtrlMac(pDevIns, pThis, pThisCC, pCtrlPktHdr, pDescChain);
     1505            break;
     1506        case VIRTIONET_CTRL_VLAN:
     1507            uAck = virtioNetR3CtrlVlan(pDevIns, pThis, pThisCC, pCtrlPktHdr, pDescChain);
     1508            break;
     1509        default:
     1510            uAck = VIRTIONET_ERROR;
     1511    }
     1512
     1513    PRTSGSEG paReqSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2);
     1514    AssertReturn(paReqSegs, VERR_NO_MEMORY);
     1515
     1516    RTSGSEG aSegs[] = { { &uAck, sizeof(uAck) } };
     1517    memcpy(paReqSegs, aSegs, sizeof(aSegs));
     1518
     1519    PRTSGBUF pReqSegBuf = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF));
     1520    AssertReturn(pReqSegBuf, VERR_NO_MEMORY);
     1521
     1522    /* Copy segment data to malloc'd memory to avoid stack out-of-scope errors sanitizer doesn't detect */
     1523    for (int i = 0; i < cSegs; i++)
     1524    {
     1525        void *pv = paReqSegs[i].pvSeg;
     1526        paReqSegs[i].pvSeg = RTMemAlloc(paReqSegs[i].cbSeg);
     1527        AssertReturn(paReqSegs[i].pvSeg, VERR_NO_MEMORY);
     1528        memcpy(paReqSegs[i].pvSeg, pv, paReqSegs[i].cbSeg);
     1529    }
     1530
     1531    RTSgBufInit(pReqSegBuf, paReqSegs, cSegs);
     1532
     1533    virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, pReqSegBuf, pDescChain, true);
     1534    virtioCoreQueueSync(pDevIns, &pThis->Virtio, qIdx);
     1535
     1536    for (int i = 0; i < cSegs; i++)
     1537        RTMemFree(paReqSegs[i].pvSeg);
     1538
     1539    RTMemFree(paReqSegs);
     1540    RTMemFree(pReqSegBuf);
     1541
     1542    LogFunc(("Processed ctrl message class/cmd/subcmd = %u/%u/%u. Ack=%u.\n",
     1543    pCtrlPktHdr.uClass, pCtrlPktHdr.uCmd, pCtrlPktHdr.uCmdSpecific, uAck);
     1544
     1545}
     1546
     1547
    9571548static void virtioNetR3Transmit(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)
    9581549{
     
    10381629}
    10391630
     1631#ifdef IN_RING3
     1632
     1633/** Returns true if large packets are written into several RX buffers. */
     1634DECLINLINE(bool) virtioNetR3MergeableRxBuffers(PVIRTIONET pThis)
     1635{
     1636    return !!(pThis->fFeatures & VIRTIONET_F_MRG_RXBUF);
     1637}
     1638
     1639DECLINLINE(int) virtioNetR3CsEnter(PPDMDEVINS pDevIns, PVIRTIONET pThis, int rcBusy)
     1640{
     1641    /* Original DevVirtioNet uses CS in attach/detach/link-up timer/tx timer/transmit */
     1642    LogFunc("CS unimplemented. What does the critical section protect in orig driver??"));
     1643}
     1644
     1645DECLINLINE(void) virtioNetR3CsLeave(PPDMDEVINS pDevIns, PVIRTIONET pThis)
     1646{
     1647    LogFunc("CS unimplemented. What does the critical section protect in orig driver??"));
     1648}
     1649
     1650/**
     1651 * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged}
     1652 */
     1653static DECLCALLBACK(void) virtioNetR3StatusChanged(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
     1654{
     1655    PVIRTIONET     pThis     = RT_FROM_MEMBER(pVirtio,  VIRTIONET, Virtio);
     1656    PVIRTIONETCC   pThisCC   = RT_FROM_MEMBER(pVirtioCC, VIRTIONETCC, Virtio);
     1657
     1658    LogFunc((""));
     1659
     1660    pThis->fVirtioReady = fVirtioReady;
     1661
     1662    if (fVirtioReady)
     1663    {
     1664        LogFunc(("VirtIO ready\n-----------------------------------------------------------------------------------------\n"));
     1665        uint64_t fFeatures   = virtioCoreGetNegotiatedFeatures(&pThis->Virtio);
     1666        pThis->fResetting    = false;
     1667        pThisCC->fQuiescing  = false;
     1668
     1669        for (unsigned i = 0; i < VIRTIONET_MAX_QUEUES; i++)
     1670            pThis->afQueueAttached[i] = true;
     1671    }
     1672    else
     1673    {
     1674        LogFunc(("VirtIO is resetting\n"));
     1675
     1676        pThis->virtioNetConfig.status = pThis->fCableConnected ? VIRTIONET_S_LINK_UP : 0;
     1677        LogFunc(("%s Link is %s\n", pThis->szInstanceName, pThis->fCableConnected ? "up" : "down"));
     1678
     1679        pThis->fPromiscuous  = true;
     1680        pThis->fAllMulticast = false;
     1681        pThis->fAllUnicast   = false;
     1682        pThis->fNoMulticat   = false;
     1683        pThis->fNoUnicast    = false;
     1684        pThis->fNoBroadcast  = false;
     1685        pThis->uIsTransmitting      = 0;
     1686        pThis->cUnicastFilterMacs   = 0;
     1687        pThis->cMulticastFilterMacs = 0;
     1688
     1689        memset(pThis->aMacMulticastFilter,  0, sizeof(pThis->aMacMulticastFilter));
     1690        memset(pThis->aMacUnicastFilter,    0, sizeof(pThis->aMacUnicastFilter));
     1691        memset(pThis->aVlanFilter,          0, sizeof(pThis->aVlanFilter));
     1692
     1693        pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true);
     1694
     1695        for (unsigned i = 0; i < VIRTIONET_MAX_QUEUES; i++)
     1696            pThis->afQueueAttached[i] = false;
     1697    }
     1698}
     1699#endif /* IN_RING3 */
     1700
    10401701/**
    10411702 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
     
    10501711
    10511712    LogFunc((""));
    1052 
    1053     AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
    1054               ("virtio-net: Device does not support hotplugging\n"));
    1055     RT_NOREF4(pThis, pThisCC, fFlags, iLUN);
     1713    AssertLogRelReturnVoid(iLUN == 0);
     1714
     1715    int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY);
     1716    AssertMsgRCReturn(rc, ("Failed to enter critical section"), rc);
    10561717
    10571718    /*
    1058      * Zero all important members.
     1719     * Zero important members.
    10591720     */
    1060     pThisCC->pDrvBase       = NULL;
     1721    pThisCC->pDrvBase = NULL;
     1722    pThisCC->pDrv     = NULL;
     1723
     1724    virtioNetR3CsLeave(pDevIns, pThis);
    10611725}
    10621726
     
    10711735    PVIRTIONETCC     pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    10721736
    1073     AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
    1074                     ("virtio-net: Device does not support hotplugging\n"),
    1075                     VERR_INVALID_PARAMETER);
     1737    RT_NOREF(fFlags);
     1738    LogFunc(("%s",  INSTANCE(pThis)));
     1739
     1740    AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
     1741
     1742    int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY);
     1743    AssertMsgRCReturn(rc, ("Failed to enter critical section"), rc);
     1744
     1745    rc = PDMDevHlpDriverAttach(pDevIns, 0, &pDevIns->IBase, &pThisCC->pDrvBase, "Network Port");
     1746    if (RT_SUCCESS(rc))
     1747    {
     1748        pThisCC->pDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMINETWORKUP);
     1749        AssertMsgStmt(pThisCC->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
     1750                      rc = VERR_PDM_MISSING_INTERFACE_BELOW);
     1751    }
     1752    else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
     1753             || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
     1754                    Log(("%s No attached driver!\n", INSTANCE(pThis)));
     1755
     1756    virtioNetR3CsLeave(pDevIns, pThis);
     1757    return rc;
    10761758
    10771759    AssertRelease(!pThisCC->pDrvBase);
    1078 
    1079     /*
    1080      * Try attach the NET driver and get the interfaces, required as well as optional.
    1081      */
    1082     int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pDevIns->IBase, &pThisCC->pDrvBase, pThis->szInstanceName);
    1083     if (RT_FAILURE(rc))
    1084         AssertMsgFailed(("Failed to attach %s. rc=%Rrc\n", pThis->szInstanceName, rc));
    1085 
    1086     if (RT_FAILURE(rc))
    1087         pThisCC->pDrvBase     = NULL;
    1088 
    10891760    return rc;
    10901761}
     
    11901861    pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface;
    11911862    pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed;
    1192     pThisCC->led.u32Magic = PDMLED_MAGIC;
     1863    pThisCC->led.uMagic = PDMLED_MAGIC;
    11931864
    11941865    /*
     
    11981869
    11991870    /* Get config params */
    1200     int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", pThis->macConfigured.au8, sizeof(pThis->macConfigured));
     1871    int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", pThis->macConfigured.au, sizeof(pThis->macConfigured));
    12011872    if (RT_FAILURE(rc))
    12021873        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get MAC address"));
     
    12061877        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the value of 'CableConnected'"));
    12071878
    1208     rc = pHlp->pfnCFGMQueryU32Def(pCfg, "LinkUpDelay", &pThis->cMsLinkUpDelay, 5000); /* ms */
     1879    uint32_t uStatNo = iInstance;
     1880    rc = pHlp->pfnCFGMQueryuDef(pCfg, "StatNo", &uStatNo, iInstance);
     1881    if (RT_FAILURE(rc))
     1882        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"StatNo\" value"));
     1883
     1884    rc = pHlp->pfnCFGMQueryuDef(pCfg, "LinkUpDelay", &pThis->cMsLinkUpDelay, 5000); /* ms */
    12091885    if (RT_FAILURE(rc))
    12101886        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the value of 'LinkUpDelay'"));
     1887
    12111888    Assert(pThis->cMsLinkUpDelay <= 300000); /* less than 5 minutes */
     1889
    12121890    if (pThis->cMsLinkUpDelay > 5000 || pThis->cMsLinkUpDelay < 100)
    1213         LogRel(("%s WARNING! Link up delay is set to %u seconds!\n", INSTANCE(pThis), pThis->cMsLinkUpDelay / 1000));
    1214     Log(("%s Link up delay is set to %u seconds\n", INSTANCE(pThis), pThis->cMsLinkUpDelay / 1000));
    1215 
    1216     uint32_t uStatNo = iInstance;
    1217     rc = pHlp->pfnCFGMQueryU32Def(pCfg, "StatNo", &uStatNo, iInstance);
    1218     if (RT_FAILURE(rc))
    1219         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"StatNo\" value"));
    1220 
    1221 
    1222     /* Initialize PCI config space */
    1223 //    memcpy(pThis->config.mac.au8, pThis->macConfigured.au8, sizeof(pThis->config.mac.au8));
    1224 //    pThis->config.uStatus = 0;
     1891        LogRel(("%s WARNING! Link up delay is set to %u seconds!\n",
     1892                pThis->szInstanceName, pThis->cMsLinkUpDelay / 1000));
     1893
     1894    Log(("%s Link up delay is set to %u seconds\n", pThis->szInstanceName, pThis->cMsLinkUpDelay / 1000));
     1895
     1896    /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */
     1897    memcpy(pThis->virtioNetConfig.uMacAddress, pThis->macConfigured.au, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */
    12251898
    12261899    /*
     
    12281901     */
    12291902
    1230     /* Configure virtio_scsi_config that transacts via VirtIO implementation's Dev. Specific Cap callbacks */
    1231     memset(pThis->virtioNetConfig.uMacAddress, 0, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */
    12321903#if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_STATUS
    1233     pThis->virtioNetConfig.uStatus          = 0;
     1904    pThis->virtioNetConfig.uStatus = 0;
    12341905#endif
     1906
    12351907#if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_MQ
    1236     pThis->virtioNetConfig.uMaxVirtqPairs   = VIRTIONET_MAX_QPAIRS;
     1908    pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS;
    12371909#endif
    12381910
     
    12601932        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated."));
    12611933
    1262     pThis->cVirtqPairs = pThis->fNegotiatedFeatures & VIRTIONET_F_MQ ? pThis->virtioNetConfig.uMaxVirtqPairs : 1;
     1934    pThis->cVirtqPairs =   pThis->fNegotiatedFeatures & VIRTIONET_F_MQ
     1935                         ? pThis->virtioNetConfig.uMaxVirtqPairs : 1;
    12631936    pThis->cVirtQueues = pThis->cVirtqPairs + 1;
     1937
    12641938    /*
    12651939     * Initialize queues.
     
    12981972    pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pUpBase, PDMILEDCONNECTORS);
    12991973
    1300 
    13011974    /*
    13021975     * Register saved state.
     
    13121985    RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance);
    13131986    PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "virtio-net info", virtioNetR3Info);
    1314 
    13151987    return rc;
    13161988}
     
    13382010const PDMDEVREG g_DeviceVirtioNet_1_0 =
    13392011{
    1340     /* .u32Version = */             PDM_DEVREG_VERSION,
     2012    /* .uVersion = */             PDM_DEVREG_VERSION,
    13412013    /* .uReserved0 = */             0,
    13422014    /* .szName = */                 "virtio-net-1-dot-0",
    1343     /* .fFlags = */                 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
     2015    /* .fFlags = */                 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE //| PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
    13442016                                    | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION
    13452017                                    | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
     
    14052077# error "Not in IN_RING3, IN_RING0 or IN_RC!"
    14062078#endif
    1407     /* .u32VersionEnd = */          PDM_DEVREG_VERSION
     2079    /* .uVersionEnd = */          PDM_DEVREG_VERSION
    14082080};
    14092081
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette