1 /* 2 * This file contains NDIS driver procedures, common for NDIS5 and NDIS6 3 * 4 * Copyright (c) 2008-2017 Red Hat, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met : 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and / or other materials provided with the distribution. 14 * 3. Neither the names of the copyright holders nor the names of their contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 #include "ndis56common.h" 30 31 #ifdef WPP_EVENT_TRACING 32 #include "ParaNdis-Common.tmh" 33 #endif 34 35 static void ReuseReceiveBufferRegular(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor); 36 static void ReuseReceiveBufferPowerOff(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor); 37 38 //#define ROUNDSIZE(sz) ((sz + 15) & ~15) 39 #define MAX_VLAN_ID 4095 40 41 #if 0 42 void FORCEINLINE DebugDumpPacket(LPCSTR prefix, PVOID header, int level) 43 { 44 PUCHAR peth = (PUCHAR)header; 45 DPrintf(level, ("[%s] %02X%02X%02X%02X%02X%02X => %02X%02X%02X%02X%02X%02X", prefix, 46 peth[6], peth[7], peth[8], peth[9], peth[10], peth[11], 47 peth[0], peth[1], peth[2], peth[3], peth[4], peth[5])); 48 } 49 #else 50 void FORCEINLINE DebugDumpPacket(LPCSTR prefix, PVOID header, int level) 51 { 52 } 53 #endif 54 55 56 57 /********************************************************** 58 Validates MAC address 59 Valid MAC address is not broadcast, not multicast, not empty 60 if bLocal is set, it must be LOCAL 61 if not, is must be non-local or local 62 Parameters: 63 PUCHAR pcMacAddress - MAC address to validate 64 BOOLEAN bLocal - TRUE, if we validate locally administered address 65 Return value: 66 TRUE if valid 67 ***********************************************************/ 68 BOOLEAN ParaNdis_ValidateMacAddress(PUCHAR pcMacAddress, BOOLEAN bLocal) 69 { 70 BOOLEAN bLA = FALSE, bEmpty, bBroadcast, bMulticast = FALSE; 71 bBroadcast = ETH_IS_BROADCAST(pcMacAddress); 72 bLA = !bBroadcast && ETH_IS_LOCALLY_ADMINISTERED(pcMacAddress); 73 bMulticast = !bBroadcast && ETH_IS_MULTICAST(pcMacAddress); 74 bEmpty = ETH_IS_EMPTY(pcMacAddress); 75 return !bBroadcast && !bEmpty && !bMulticast && (!bLocal || bLA); 76 } 77 78 static eInspectedPacketType QueryPacketType(PVOID data) 79 { 80 if (ETH_IS_BROADCAST(data)) 81 return iptBroadcast; 82 if (ETH_IS_MULTICAST(data)) 83 return iptMulticast; 84 return iptUnicast; 85 } 86 87 typedef struct _tagConfigurationEntry 88 { 89 const char *Name; 90 ULONG ulValue; 91 ULONG ulMinimal; 92 ULONG ulMaximal; 93 }tConfigurationEntry; 94 95 typedef struct _tagConfigurationEntries 96 { 97 tConfigurationEntry isPromiscuous; 98 tConfigurationEntry PrioritySupport; 99 tConfigurationEntry ConnectRate; 100 tConfigurationEntry isLogEnabled; 101 tConfigurationEntry debugLevel; 102 tConfigurationEntry connectTimer; 103 tConfigurationEntry dpcChecker; 104 tConfigurationEntry TxCapacity; 105 tConfigurationEntry RxCapacity; 106 tConfigurationEntry InterruptRecovery; 107 tConfigurationEntry LogStatistics; 108 tConfigurationEntry PacketFiltering; 109 tConfigurationEntry ScatterGather; 110 tConfigurationEntry BatchReceive; 111 tConfigurationEntry OffloadTxChecksum; 112 tConfigurationEntry OffloadTxLSO; 113 tConfigurationEntry OffloadRxCS; 114 tConfigurationEntry OffloadGuestCS; 115 tConfigurationEntry UseSwTxChecksum; 116 tConfigurationEntry IPPacketsCheck; 117 tConfigurationEntry stdIpcsV4; 118 tConfigurationEntry stdTcpcsV4; 119 tConfigurationEntry stdTcpcsV6; 120 tConfigurationEntry stdUdpcsV4; 121 tConfigurationEntry stdUdpcsV6; 122 tConfigurationEntry stdLsoV1; 123 tConfigurationEntry stdLsoV2ip4; 124 tConfigurationEntry stdLsoV2ip6; 125 tConfigurationEntry PriorityVlanTagging; 126 tConfigurationEntry VlanId; 127 tConfigurationEntry UseMergeableBuffers; 128 tConfigurationEntry MTU; 129 tConfigurationEntry NumberOfHandledRXPackersInDPC; 130 tConfigurationEntry Indirect; 131 }tConfigurationEntries; 132 133 static const tConfigurationEntries defaultConfiguration = 134 { 135 { "Promiscuous", 0, 0, 1 }, 136 { "Priority", 0, 0, 1 }, 137 { "ConnectRate", 100,10,10000 }, 138 { "DoLog", 1, 0, 1 }, 139 { "DebugLevel", 2, 0, 8 }, 140 { "ConnectTimer", 0, 0, 300000 }, 141 { "DpcCheck", 0, 0, 2 }, 142 { "TxCapacity", 1024, 16, 1024 }, 143 { "RxCapacity", 256, 32, 1024 }, 144 { "InterruptRecovery", 0, 0, 1}, 145 { "LogStatistics", 0, 0, 10000}, 146 { "PacketFilter", 1, 0, 1}, 147 { "Gather", 1, 0, 1}, 148 { "BatchReceive", 1, 0, 1}, 149 { "Offload.TxChecksum", 0, 0, 31}, 150 { "Offload.TxLSO", 0, 0, 2}, 151 { "Offload.RxCS", 0, 0, 31}, 152 { "Offload.GuestCS", 0, 0, 1}, 153 { "UseSwTxChecksum", 0, 0, 1 }, 154 { "IPPacketsCheck", 0, 0, 3 }, 155 { "*IPChecksumOffloadIPv4", 3, 0, 3 }, 156 { "*TCPChecksumOffloadIPv4",3, 0, 3 }, 157 { "*TCPChecksumOffloadIPv6",3, 0, 3 }, 158 { "*UDPChecksumOffloadIPv4",3, 0, 3 }, 159 { "*UDPChecksumOffloadIPv6",3, 0, 3 }, 160 { "*LsoV1IPv4", 1, 0, 1 }, 161 { "*LsoV2IPv4", 1, 0, 1 }, 162 { "*LsoV2IPv6", 1, 0, 1 }, 163 { "*PriorityVLANTag", 3, 0, 3}, 164 { "VlanId", 0, 0, MAX_VLAN_ID}, 165 { "MergeableBuf", 1, 0, 1}, 166 { "MTU", 1500, 500, 65500}, 167 { "NumberOfHandledRXPackersInDPC", MAX_RX_LOOPS, 1, 10000}, 168 { "Indirect", 0, 0, 2}, 169 }; 170 171 static void ParaNdis_ResetVirtIONetDevice(PARANDIS_ADAPTER *pContext) 172 { 173 virtio_device_reset(&pContext->IODevice); 174 DPrintf(0, ("[%s] Done", __FUNCTION__)); 175 /* reset all the features in the device */ 176 pContext->ulCurrentVlansFilterSet = 0; 177 pContext->ullGuestFeatures = 0; 178 #ifdef VIRTIO_RESET_VERIFY 179 if (1) 180 { 181 u8 devStatus; 182 devStatus = virtio_get_status(&pContext->IODevice); 183 if (devStatus) 184 { 185 DPrintf(0, ("[%s] Device status is still %02X", __FUNCTION__, (ULONG)devStatus)); 186 virtio_device_reset(&pContext->IODevice); 187 devStatus = virtio_get_status(&pContext->IODevice); 188 DPrintf(0, ("[%s] Device status on retry %02X", __FUNCTION__, (ULONG)devStatus)); 189 } 190 } 191 #endif 192 } 193 194 /********************************************************** 195 Gets integer value for specifies in pEntry->Name name 196 Parameters: 197 NDIS_HANDLE cfg previously open configuration 198 tConfigurationEntry *pEntry - Entry to fill value in 199 ***********************************************************/ 200 static void GetConfigurationEntry(NDIS_HANDLE cfg, tConfigurationEntry *pEntry) 201 { 202 NDIS_STATUS status; 203 const char *statusName; 204 NDIS_STRING name = {0}; 205 PNDIS_CONFIGURATION_PARAMETER pParam = NULL; 206 NDIS_PARAMETER_TYPE ParameterType = NdisParameterInteger; 207 NdisInitializeString(&name, (PUCHAR)pEntry->Name); 208 NdisReadConfiguration( 209 &status, 210 &pParam, 211 cfg, 212 &name, 213 ParameterType); 214 if (status == NDIS_STATUS_SUCCESS) 215 { 216 ULONG ulValue = pParam->ParameterData.IntegerData; 217 if (ulValue >= pEntry->ulMinimal && ulValue <= pEntry->ulMaximal) 218 { 219 pEntry->ulValue = ulValue; 220 statusName = "value"; 221 } 222 else 223 { 224 statusName = "out of range"; 225 } 226 } 227 else 228 { 229 statusName = "nothing"; 230 } 231 DPrintf(2, ("[%s] %s read for %s - 0x%x", 232 __FUNCTION__, 233 statusName, 234 pEntry->Name, 235 pEntry->ulValue)); 236 if (name.Buffer) NdisFreeString(name); 237 } 238 239 static void DisableLSOv4Permanently(PARANDIS_ADAPTER *pContext, LPCSTR procname, LPCSTR reason) 240 { 241 if (pContext->Offload.flagsValue & osbT4Lso) 242 { 243 DPrintf(0, ("[%s] Warning: %s", procname, reason)); 244 pContext->Offload.flagsValue &= ~osbT4Lso; 245 ParaNdis_ResetOffloadSettings(pContext, NULL, NULL); 246 } 247 } 248 249 static void DisableLSOv6Permanently(PARANDIS_ADAPTER *pContext, LPCSTR procname, LPCSTR reason) 250 { 251 if (pContext->Offload.flagsValue & osbT6Lso) 252 { 253 DPrintf(0, ("[%s] Warning: %s", procname, reason)); 254 pContext->Offload.flagsValue &= ~osbT6Lso; 255 ParaNdis_ResetOffloadSettings(pContext, NULL, NULL); 256 } 257 } 258 259 static void DisableBothLSOPermanently(PARANDIS_ADAPTER *pContext, LPCSTR procname, LPCSTR reason) 260 { 261 if (pContext->Offload.flagsValue & (osbT4Lso | osbT6Lso)) 262 { 263 DPrintf(0, ("[%s] Warning: %s", procname, reason)); 264 pContext->Offload.flagsValue &= ~(osbT6Lso | osbT4Lso); 265 ParaNdis_ResetOffloadSettings(pContext, NULL, NULL); 266 } 267 } 268 269 /********************************************************** 270 Loads NIC parameters from adapter registry key 271 Parameters: 272 context 273 PUCHAR *ppNewMACAddress - pointer to hold MAC address if configured from host 274 ***********************************************************/ 275 static void ReadNicConfiguration(PARANDIS_ADAPTER *pContext, PUCHAR *ppNewMACAddress) 276 { 277 NDIS_HANDLE cfg; 278 tConfigurationEntries *pConfiguration = ParaNdis_AllocateMemory(pContext, sizeof(tConfigurationEntries)); 279 if (pConfiguration) 280 { 281 *pConfiguration = defaultConfiguration; 282 cfg = ParaNdis_OpenNICConfiguration(pContext); 283 if (cfg) 284 { 285 GetConfigurationEntry(cfg, &pConfiguration->isLogEnabled); 286 GetConfigurationEntry(cfg, &pConfiguration->debugLevel); 287 GetConfigurationEntry(cfg, &pConfiguration->ConnectRate); 288 GetConfigurationEntry(cfg, &pConfiguration->PrioritySupport); 289 GetConfigurationEntry(cfg, &pConfiguration->isPromiscuous); 290 GetConfigurationEntry(cfg, &pConfiguration->TxCapacity); 291 GetConfigurationEntry(cfg, &pConfiguration->RxCapacity); 292 GetConfigurationEntry(cfg, &pConfiguration->connectTimer); 293 GetConfigurationEntry(cfg, &pConfiguration->dpcChecker); 294 GetConfigurationEntry(cfg, &pConfiguration->InterruptRecovery); 295 GetConfigurationEntry(cfg, &pConfiguration->LogStatistics); 296 GetConfigurationEntry(cfg, &pConfiguration->PacketFiltering); 297 GetConfigurationEntry(cfg, &pConfiguration->ScatterGather); 298 GetConfigurationEntry(cfg, &pConfiguration->BatchReceive); 299 GetConfigurationEntry(cfg, &pConfiguration->OffloadTxChecksum); 300 GetConfigurationEntry(cfg, &pConfiguration->OffloadTxLSO); 301 GetConfigurationEntry(cfg, &pConfiguration->OffloadRxCS); 302 GetConfigurationEntry(cfg, &pConfiguration->OffloadGuestCS); 303 GetConfigurationEntry(cfg, &pConfiguration->UseSwTxChecksum); 304 GetConfigurationEntry(cfg, &pConfiguration->IPPacketsCheck); 305 GetConfigurationEntry(cfg, &pConfiguration->stdIpcsV4); 306 GetConfigurationEntry(cfg, &pConfiguration->stdTcpcsV4); 307 GetConfigurationEntry(cfg, &pConfiguration->stdTcpcsV6); 308 GetConfigurationEntry(cfg, &pConfiguration->stdUdpcsV4); 309 GetConfigurationEntry(cfg, &pConfiguration->stdUdpcsV6); 310 GetConfigurationEntry(cfg, &pConfiguration->stdLsoV1); 311 GetConfigurationEntry(cfg, &pConfiguration->stdLsoV2ip4); 312 GetConfigurationEntry(cfg, &pConfiguration->stdLsoV2ip6); 313 GetConfigurationEntry(cfg, &pConfiguration->PriorityVlanTagging); 314 GetConfigurationEntry(cfg, &pConfiguration->VlanId); 315 GetConfigurationEntry(cfg, &pConfiguration->UseMergeableBuffers); 316 GetConfigurationEntry(cfg, &pConfiguration->MTU); 317 GetConfigurationEntry(cfg, &pConfiguration->NumberOfHandledRXPackersInDPC); 318 GetConfigurationEntry(cfg, &pConfiguration->Indirect); 319 320 #if !defined(WPP_EVENT_TRACING) 321 bDebugPrint = pConfiguration->isLogEnabled.ulValue; 322 nDebugLevel = pConfiguration->debugLevel.ulValue; 323 #endif 324 // ignoring promiscuous setting, nothing to do with it 325 pContext->maxFreeTxDescriptors = pConfiguration->TxCapacity.ulValue; 326 pContext->NetMaxReceiveBuffers = pConfiguration->RxCapacity.ulValue; 327 pContext->ulMilliesToConnect = pConfiguration->connectTimer.ulValue; 328 pContext->nEnableDPCChecker = pConfiguration->dpcChecker.ulValue; 329 pContext->bDoInterruptRecovery = pConfiguration->InterruptRecovery.ulValue != 0; 330 pContext->Limits.nPrintDiagnostic = pConfiguration->LogStatistics.ulValue; 331 pContext->uNumberOfHandledRXPacketsInDPC = pConfiguration->NumberOfHandledRXPackersInDPC.ulValue; 332 pContext->bDoSupportPriority = pConfiguration->PrioritySupport.ulValue != 0; 333 pContext->ulFormalLinkSpeed = pConfiguration->ConnectRate.ulValue; 334 pContext->ulFormalLinkSpeed *= 1000000; 335 pContext->bDoHwPacketFiltering = pConfiguration->PacketFiltering.ulValue != 0; 336 pContext->bUseScatterGather = pConfiguration->ScatterGather.ulValue != 0; 337 pContext->bBatchReceive = pConfiguration->BatchReceive.ulValue != 0; 338 pContext->bDoHardwareChecksum = pConfiguration->UseSwTxChecksum.ulValue == 0; 339 pContext->bDoGuestChecksumOnReceive = pConfiguration->OffloadGuestCS.ulValue != 0; 340 pContext->bDoIPCheckTx = pConfiguration->IPPacketsCheck.ulValue & 1; 341 pContext->bDoIPCheckRx = pConfiguration->IPPacketsCheck.ulValue & 2; 342 pContext->Offload.flagsValue = 0; 343 // TX caps: 1 - TCP, 2 - UDP, 4 - IP, 8 - TCPv6, 16 - UDPv6 344 if (pConfiguration->OffloadTxChecksum.ulValue & 1) pContext->Offload.flagsValue |= osbT4TcpChecksum | osbT4TcpOptionsChecksum; 345 if (pConfiguration->OffloadTxChecksum.ulValue & 2) pContext->Offload.flagsValue |= osbT4UdpChecksum; 346 if (pConfiguration->OffloadTxChecksum.ulValue & 4) pContext->Offload.flagsValue |= osbT4IpChecksum | osbT4IpOptionsChecksum; 347 if (pConfiguration->OffloadTxChecksum.ulValue & 8) pContext->Offload.flagsValue |= osbT6TcpChecksum | osbT6TcpOptionsChecksum; 348 if (pConfiguration->OffloadTxChecksum.ulValue & 16) pContext->Offload.flagsValue |= osbT6UdpChecksum; 349 if (pConfiguration->OffloadTxLSO.ulValue) pContext->Offload.flagsValue |= osbT4Lso | osbT4LsoIp | osbT4LsoTcp; 350 if (pConfiguration->OffloadTxLSO.ulValue > 1) pContext->Offload.flagsValue |= osbT6Lso | osbT6LsoTcpOptions; 351 // RX caps: 1 - TCP, 2 - UDP, 4 - IP, 8 - TCPv6, 16 - UDPv6 352 if (pConfiguration->OffloadRxCS.ulValue & 1) pContext->Offload.flagsValue |= osbT4RxTCPChecksum | osbT4RxTCPOptionsChecksum; 353 if (pConfiguration->OffloadRxCS.ulValue & 2) pContext->Offload.flagsValue |= osbT4RxUDPChecksum; 354 if (pConfiguration->OffloadRxCS.ulValue & 4) pContext->Offload.flagsValue |= osbT4RxIPChecksum | osbT4RxIPOptionsChecksum; 355 if (pConfiguration->OffloadRxCS.ulValue & 8) pContext->Offload.flagsValue |= osbT6RxTCPChecksum | osbT6RxTCPOptionsChecksum; 356 if (pConfiguration->OffloadRxCS.ulValue & 16) pContext->Offload.flagsValue |= osbT6RxUDPChecksum; 357 /* full packet size that can be configured as GSO for VIRTIO is short */ 358 /* NDIS test fails sometimes fails on segments 50-60K */ 359 pContext->Offload.maxPacketSize = PARANDIS_MAX_LSO_SIZE; 360 pContext->InitialOffloadParameters.IPv4Checksum = (UCHAR)pConfiguration->stdIpcsV4.ulValue; 361 pContext->InitialOffloadParameters.TCPIPv4Checksum = (UCHAR)pConfiguration->stdTcpcsV4.ulValue; 362 pContext->InitialOffloadParameters.TCPIPv6Checksum = (UCHAR)pConfiguration->stdTcpcsV6.ulValue; 363 pContext->InitialOffloadParameters.UDPIPv4Checksum = (UCHAR)pConfiguration->stdUdpcsV4.ulValue; 364 pContext->InitialOffloadParameters.UDPIPv6Checksum = (UCHAR)pConfiguration->stdUdpcsV6.ulValue; 365 pContext->InitialOffloadParameters.LsoV1 = (UCHAR)pConfiguration->stdLsoV1.ulValue; 366 pContext->InitialOffloadParameters.LsoV2IPv4 = (UCHAR)pConfiguration->stdLsoV2ip4.ulValue; 367 pContext->InitialOffloadParameters.LsoV2IPv6 = (UCHAR)pConfiguration->stdLsoV2ip6.ulValue; 368 pContext->ulPriorityVlanSetting = pConfiguration->PriorityVlanTagging.ulValue; 369 pContext->VlanId = pConfiguration->VlanId.ulValue & 0xfff; 370 pContext->bUseMergedBuffers = pConfiguration->UseMergeableBuffers.ulValue != 0; 371 pContext->MaxPacketSize.nMaxDataSize = pConfiguration->MTU.ulValue; 372 pContext->bUseIndirect = pConfiguration->Indirect.ulValue != 0; 373 if (!pContext->bDoSupportPriority) 374 pContext->ulPriorityVlanSetting = 0; 375 // if Vlan not supported 376 if (!IsVlanSupported(pContext)) 377 pContext->VlanId = 0; 378 if (1) 379 { 380 NDIS_STATUS status; 381 PVOID p; 382 UINT len = 0; 383 NdisReadNetworkAddress(&status, &p, &len, cfg); 384 if (status == NDIS_STATUS_SUCCESS && len == sizeof(pContext->CurrentMacAddress)) 385 { 386 *ppNewMACAddress = ParaNdis_AllocateMemory(pContext, sizeof(pContext->CurrentMacAddress)); 387 if (*ppNewMACAddress) 388 { 389 NdisMoveMemory(*ppNewMACAddress, p, len); 390 } 391 else 392 { 393 DPrintf(0, ("[%s] MAC address present, but some problem also...", __FUNCTION__)); 394 } 395 } 396 else if (len && len != sizeof(pContext->CurrentMacAddress)) 397 { 398 DPrintf(0, ("[%s] MAC address has wrong length of %d", __FUNCTION__, len)); 399 } 400 else 401 { 402 DPrintf(4, ("[%s] Nothing read for MAC, error %X", __FUNCTION__, status)); 403 } 404 } 405 NdisCloseConfiguration(cfg); 406 } 407 NdisFreeMemory(pConfiguration, 0, 0); 408 } 409 } 410 411 void ParaNdis_ResetOffloadSettings(PARANDIS_ADAPTER *pContext, tOffloadSettingsFlags *pDest, PULONG from) 412 { 413 if (!pDest) pDest = &pContext->Offload.flags; 414 if (!from) from = &pContext->Offload.flagsValue; 415 416 pDest->fTxIPChecksum = !!(*from & osbT4IpChecksum); 417 pDest->fTxTCPChecksum = !!(*from & osbT4TcpChecksum); 418 pDest->fTxUDPChecksum = !!(*from & osbT4UdpChecksum); 419 pDest->fTxTCPOptions = !!(*from & osbT4TcpOptionsChecksum); 420 pDest->fTxIPOptions = !!(*from & osbT4IpOptionsChecksum); 421 422 pDest->fTxLso = !!(*from & osbT4Lso); 423 pDest->fTxLsoIP = !!(*from & osbT4LsoIp); 424 pDest->fTxLsoTCP = !!(*from & osbT4LsoTcp); 425 426 pDest->fRxIPChecksum = !!(*from & osbT4RxIPChecksum); 427 pDest->fRxIPOptions = !!(*from & osbT4RxIPOptionsChecksum); 428 pDest->fRxTCPChecksum = !!(*from & osbT4RxTCPChecksum); 429 pDest->fRxTCPOptions = !!(*from & osbT4RxTCPOptionsChecksum); 430 pDest->fRxUDPChecksum = !!(*from & osbT4RxUDPChecksum); 431 432 pDest->fTxTCPv6Checksum = !!(*from & osbT6TcpChecksum); 433 pDest->fTxTCPv6Options = !!(*from & osbT6TcpOptionsChecksum); 434 pDest->fTxUDPv6Checksum = !!(*from & osbT6UdpChecksum); 435 pDest->fTxIPv6Ext = !!(*from & osbT6IpExtChecksum); 436 437 pDest->fTxLsov6 = !!(*from & osbT6Lso); 438 pDest->fTxLsov6IP = !!(*from & osbT6LsoIpExt); 439 pDest->fTxLsov6TCP = !!(*from & osbT6LsoTcpOptions); 440 441 pDest->fRxTCPv6Checksum = !!(*from & osbT6RxTCPChecksum); 442 pDest->fRxTCPv6Options = !!(*from & osbT6RxTCPOptionsChecksum); 443 pDest->fRxUDPv6Checksum = !!(*from & osbT6RxUDPChecksum); 444 pDest->fRxIPv6Ext = !!(*from & osbT6RxIpExtChecksum); 445 } 446 447 /********************************************************** 448 Enumerates adapter resources and fills the structure holding them 449 Verifies that IO assigned and has correct size 450 Verifies that interrupt assigned 451 Parameters: 452 PNDIS_RESOURCE_LIST RList - list of resources, received from NDIS 453 tAdapterResources *pResources - structure to fill 454 Return value: 455 TRUE if everything is OK 456 ***********************************************************/ 457 static BOOLEAN GetAdapterResources(NDIS_HANDLE MiniportHandle, PNDIS_RESOURCE_LIST RList, tAdapterResources *pResources) 458 { 459 UINT i; 460 int read, bar = -1; 461 PCI_COMMON_HEADER pci_config; 462 NdisZeroMemory(pResources, sizeof(*pResources)); 463 464 // read the PCI config space header 465 read = NdisReadPciSlotInformation( 466 MiniportHandle, 467 0 /* SlotNumber, reserved */, 468 0 /* Offset */, 469 &pci_config, 470 sizeof(pci_config)); 471 if (read != sizeof(pci_config)) { 472 return FALSE; 473 } 474 475 for (i = 0; i < RList->Count; ++i) 476 { 477 ULONG type = RList->PartialDescriptors[i].Type; 478 if (type == CmResourceTypePort) 479 { 480 PHYSICAL_ADDRESS Start = RList->PartialDescriptors[i].u.Port.Start; 481 ULONG len = RList->PartialDescriptors[i].u.Port.Length; 482 DPrintf(0, ("Found IO ports at %08lX(%d)", Start.LowPart, len)); 483 bar = virtio_get_bar_index(&pci_config, Start); 484 if (bar < 0) { 485 break; 486 } 487 pResources->PciBars[bar].BasePA = Start; 488 pResources->PciBars[bar].uLength = len; 489 pResources->PciBars[bar].bPortSpace = TRUE; 490 } 491 else if (type == CmResourceTypeMemory) 492 { 493 PHYSICAL_ADDRESS Start = RList->PartialDescriptors[i].u.Memory.Start; 494 ULONG len = RList->PartialDescriptors[i].u.Memory.Length; 495 DPrintf(0, ("Found IO memory at %08I64X(%d)", Start.QuadPart, len)); 496 bar = virtio_get_bar_index(&pci_config, Start); 497 if (bar < 0) { 498 break; 499 } 500 pResources->PciBars[bar].BasePA = Start; 501 pResources->PciBars[bar].uLength = len; 502 pResources->PciBars[bar].bPortSpace = FALSE; 503 } 504 else if (type == CmResourceTypeInterrupt) 505 { 506 pResources->Vector = RList->PartialDescriptors[i].u.Interrupt.Vector; 507 pResources->Level = RList->PartialDescriptors[i].u.Interrupt.Level; 508 pResources->Affinity = RList->PartialDescriptors[i].u.Interrupt.Affinity; 509 pResources->InterruptFlags = RList->PartialDescriptors[i].Flags; 510 DPrintf(0, ("Found Interrupt vector %d, level %d, affinity %X, flags %X", 511 pResources->Vector, pResources->Level, (ULONG)pResources->Affinity, pResources->InterruptFlags)); 512 } 513 } 514 return bar >= 0 && pResources->Vector; 515 } 516 517 static void DumpVirtIOFeatures(PARANDIS_ADAPTER *pContext) 518 { 519 const struct { ULONG bitmask; const PCHAR Name; } Features[] = 520 { 521 522 {VIRTIO_NET_F_CSUM, "VIRTIO_NET_F_CSUM" }, 523 {VIRTIO_NET_F_GUEST_CSUM, "VIRTIO_NET_F_GUEST_CSUM" }, 524 {VIRTIO_NET_F_MAC, "VIRTIO_NET_F_MAC" }, 525 {VIRTIO_NET_F_GSO, "VIRTIO_NET_F_GSO" }, 526 {VIRTIO_NET_F_GUEST_TSO4, "VIRTIO_NET_F_GUEST_TSO4"}, 527 {VIRTIO_NET_F_GUEST_TSO6, "VIRTIO_NET_F_GUEST_TSO6"}, 528 {VIRTIO_NET_F_GUEST_ECN, "VIRTIO_NET_F_GUEST_ECN"}, 529 {VIRTIO_NET_F_GUEST_UFO, "VIRTIO_NET_F_GUEST_UFO"}, 530 {VIRTIO_NET_F_HOST_TSO4, "VIRTIO_NET_F_HOST_TSO4"}, 531 {VIRTIO_NET_F_HOST_TSO6, "VIRTIO_NET_F_HOST_TSO6"}, 532 {VIRTIO_NET_F_HOST_ECN, "VIRTIO_NET_F_HOST_ECN"}, 533 {VIRTIO_NET_F_HOST_UFO, "VIRTIO_NET_F_HOST_UFO"}, 534 {VIRTIO_NET_F_MRG_RXBUF, "VIRTIO_NET_F_MRG_RXBUF"}, 535 {VIRTIO_NET_F_STATUS, "VIRTIO_NET_F_STATUS"}, 536 {VIRTIO_NET_F_CTRL_VQ, "VIRTIO_NET_F_CTRL_VQ"}, 537 {VIRTIO_NET_F_CTRL_RX, "VIRTIO_NET_F_CTRL_RX"}, 538 {VIRTIO_NET_F_CTRL_VLAN, "VIRTIO_NET_F_CTRL_VLAN"}, 539 {VIRTIO_NET_F_CTRL_RX_EXTRA, "VIRTIO_NET_F_CTRL_RX_EXTRA"}, 540 {VIRTIO_RING_F_INDIRECT_DESC, "VIRTIO_RING_F_INDIRECT_DESC"}, 541 {VIRTIO_F_VERSION_1, "VIRTIO_F_VERSION_1" }, 542 {VIRTIO_F_ANY_LAYOUT, "VIRTIO_F_ANY_LAYOUT" }, 543 }; 544 UINT i; 545 for (i = 0; i < sizeof(Features)/sizeof(Features[0]); ++i) 546 { 547 if (VirtIODeviceGetHostFeature(pContext, Features[i].bitmask)) 548 { 549 DPrintf(0, ("VirtIO Host Feature %s", Features[i].Name)); 550 } 551 } 552 } 553 554 /********************************************************** 555 Only for test. Prints out if the interrupt line is ON 556 Parameters: 557 Return value: 558 ***********************************************************/ 559 static void JustForCheckClearInterrupt(PARANDIS_ADAPTER *pContext, const char *Label) 560 { 561 if (pContext->bEnableInterruptChecking) 562 { 563 ULONG ulActive; 564 ulActive = virtio_read_isr_status(&pContext->IODevice); 565 if (ulActive) 566 { 567 DPrintf(0,("WARNING: Interrupt Line %d(%s)!", ulActive, Label)); 568 } 569 } 570 } 571 572 /********************************************************** 573 Prints out statistics 574 ***********************************************************/ 575 static void PrintStatistics(PARANDIS_ADAPTER *pContext) 576 { 577 ULONG64 totalTxFrames = 578 pContext->Statistics.ifHCOutBroadcastPkts + 579 pContext->Statistics.ifHCOutMulticastPkts + 580 pContext->Statistics.ifHCOutUcastPkts; 581 ULONG64 totalRxFrames = 582 pContext->Statistics.ifHCInBroadcastPkts + 583 pContext->Statistics.ifHCInMulticastPkts + 584 pContext->Statistics.ifHCInUcastPkts; 585 586 DPrintf(0, ("[Diag!%X] RX buffers at VIRTIO %d of %d", 587 pContext->CurrentMacAddress[5], 588 pContext->NetNofReceiveBuffers, 589 pContext->NetMaxReceiveBuffers)); 590 DPrintf(0, ("[Diag!] TX desc available %d/%d, buf %d/min. %d", 591 pContext->nofFreeTxDescriptors, 592 pContext->maxFreeTxDescriptors, 593 pContext->nofFreeHardwareBuffers, 594 pContext->minFreeHardwareBuffers)); 595 pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers; 596 if (pContext->NetTxPacketsToReturn) 597 { 598 DPrintf(0, ("[Diag!] TX packets to return %d", pContext->NetTxPacketsToReturn)); 599 } 600 DPrintf(0, ("[Diag!] Bytes transmitted %I64u, received %I64u", 601 pContext->Statistics.ifHCOutOctets, 602 pContext->Statistics.ifHCInOctets)); 603 DPrintf(0, ("[Diag!] Tx frames %I64u, CSO %d, LSO %d, indirect %d", 604 totalTxFrames, 605 pContext->extraStatistics.framesCSOffload, 606 pContext->extraStatistics.framesLSO, 607 pContext->extraStatistics.framesIndirect)); 608 DPrintf(0, ("[Diag!] Rx frames %I64u, Rx.Pri %d, RxHwCS.OK %d, FiltOut %d", 609 totalRxFrames, pContext->extraStatistics.framesRxPriority, 610 pContext->extraStatistics.framesRxCSHwOK, pContext->extraStatistics.framesFilteredOut)); 611 if (pContext->extraStatistics.framesRxCSHwMissedBad || pContext->extraStatistics.framesRxCSHwMissedGood) 612 { 613 DPrintf(0, ("[Diag!] RxHwCS mistakes: missed bad %d, missed good %d", 614 pContext->extraStatistics.framesRxCSHwMissedBad, pContext->extraStatistics.framesRxCSHwMissedGood)); 615 } 616 } 617 618 static NDIS_STATUS NTStatusToNdisStatus(NTSTATUS nt_status) { 619 switch (nt_status) { 620 case STATUS_SUCCESS: 621 return NDIS_STATUS_SUCCESS; 622 case STATUS_NOT_FOUND: 623 case STATUS_DEVICE_NOT_CONNECTED: 624 return NDIS_STATUS_ADAPTER_NOT_FOUND; 625 case STATUS_INSUFFICIENT_RESOURCES: 626 return NDIS_STATUS_RESOURCES; 627 case STATUS_INVALID_PARAMETER: 628 return NDIS_STATUS_INVALID_DEVICE_REQUEST; 629 default: 630 return NDIS_STATUS_FAILURE; 631 } 632 } 633 634 static NDIS_STATUS FinalizeFeatures(PARANDIS_ADAPTER *pContext) 635 { 636 NTSTATUS nt_status = virtio_set_features(&pContext->IODevice, pContext->ullGuestFeatures); 637 if (!NT_SUCCESS(nt_status)) { 638 DPrintf(0, ("[%s] virtio_set_features failed with %x\n", __FUNCTION__, nt_status)); 639 } 640 return NTStatusToNdisStatus(nt_status); 641 } 642 643 /********************************************************** 644 Initializes the context structure 645 Major variables, received from NDIS on initialization, must be be set before this call 646 (for ex. pContext->MiniportHandle) 647 648 If this procedure fails, no need to call 649 ParaNdis_CleanupContext 650 651 652 Parameters: 653 Return value: 654 SUCCESS, if resources are OK 655 NDIS_STATUS_RESOURCE_CONFLICT if not 656 ***********************************************************/ 657 NDIS_STATUS ParaNdis_InitializeContext( 658 PARANDIS_ADAPTER *pContext, 659 PNDIS_RESOURCE_LIST pResourceList) 660 { 661 NDIS_STATUS status = NDIS_STATUS_SUCCESS; 662 PUCHAR pNewMacAddress = NULL; 663 USHORT linkStatus = 0; 664 NTSTATUS nt_status; 665 666 DEBUG_ENTRY(0); 667 /* read first PCI IO bar*/ 668 //ulIOAddress = ReadPCIConfiguration(miniportAdapterHandle, 0x10); 669 /* check this is IO and assigned */ 670 ReadNicConfiguration(pContext, &pNewMacAddress); 671 if (pNewMacAddress) 672 { 673 if (ParaNdis_ValidateMacAddress(pNewMacAddress, TRUE)) 674 { 675 DPrintf(0, ("[%s] WARNING: MAC address reloaded", __FUNCTION__)); 676 NdisMoveMemory(pContext->CurrentMacAddress, pNewMacAddress, sizeof(pContext->CurrentMacAddress)); 677 } 678 else 679 { 680 DPrintf(0, ("[%s] WARNING: Invalid MAC address ignored", __FUNCTION__)); 681 } 682 NdisFreeMemory(pNewMacAddress, 0, 0); 683 } 684 685 pContext->MaxPacketSize.nMaxFullSizeOS = pContext->MaxPacketSize.nMaxDataSize + ETH_HEADER_SIZE; 686 pContext->MaxPacketSize.nMaxFullSizeHwTx = pContext->MaxPacketSize.nMaxFullSizeOS; 687 pContext->MaxPacketSize.nMaxFullSizeHwRx = pContext->MaxPacketSize.nMaxFullSizeOS + ETH_PRIORITY_HEADER_SIZE; 688 if (pContext->ulPriorityVlanSetting) 689 pContext->MaxPacketSize.nMaxFullSizeHwTx = pContext->MaxPacketSize.nMaxFullSizeHwRx; 690 691 if (GetAdapterResources(pContext->MiniportHandle, pResourceList, &pContext->AdapterResources)) 692 { 693 if (pContext->AdapterResources.InterruptFlags & CM_RESOURCE_INTERRUPT_MESSAGE) 694 { 695 DPrintf(0, ("[%s] Message interrupt assigned", __FUNCTION__)); 696 pContext->bUsingMSIX = TRUE; 697 } 698 699 nt_status = virtio_device_initialize( 700 &pContext->IODevice, 701 &ParaNdisSystemOps, 702 pContext, 703 pContext->bUsingMSIX); 704 if (!NT_SUCCESS(nt_status)) { 705 DPrintf(0, ("[%s] virtio_device_initialize failed with %x\n", __FUNCTION__, nt_status)); 706 status = NTStatusToNdisStatus(nt_status); 707 DEBUG_EXIT_STATUS(0, status); 708 return status; 709 } 710 711 pContext->bIODeviceInitialized = TRUE; 712 JustForCheckClearInterrupt(pContext, "init 0"); 713 ParaNdis_ResetVirtIONetDevice(pContext); 714 JustForCheckClearInterrupt(pContext, "init 1"); 715 virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE); 716 JustForCheckClearInterrupt(pContext, "init 2"); 717 virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_DRIVER); 718 pContext->ullHostFeatures = virtio_get_features(&pContext->IODevice); 719 DumpVirtIOFeatures(pContext); 720 JustForCheckClearInterrupt(pContext, "init 3"); 721 pContext->bLinkDetectSupported = 0 != VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_STATUS); 722 723 if(pContext->bLinkDetectSupported) { 724 virtio_get_config(&pContext->IODevice, sizeof(pContext->CurrentMacAddress), &linkStatus, sizeof(linkStatus)); 725 pContext->bConnected = (linkStatus & VIRTIO_NET_S_LINK_UP) != 0; 726 DPrintf(0, ("[%s] Link status on driver startup: %d", __FUNCTION__, pContext->bConnected)); 727 } 728 729 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_VERSION_1)) 730 { 731 // virtio 1.0 always uses the extended header 732 pContext->nVirtioHeaderSize = sizeof(virtio_net_hdr_ext); 733 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_VERSION_1); 734 } 735 else 736 { 737 pContext->nVirtioHeaderSize = sizeof(virtio_net_hdr_basic); 738 } 739 740 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_ANY_LAYOUT)) 741 { 742 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_ANY_LAYOUT); 743 } 744 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_RING_F_EVENT_IDX)) 745 { 746 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_RING_F_EVENT_IDX); 747 } 748 749 if (!pContext->bUseMergedBuffers && VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_MRG_RXBUF)) 750 { 751 DPrintf(0, ("[%s] Not using mergeable buffers", __FUNCTION__)); 752 } 753 else 754 { 755 pContext->bUseMergedBuffers = VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_MRG_RXBUF) != 0; 756 if (pContext->bUseMergedBuffers) 757 { 758 pContext->nVirtioHeaderSize = sizeof(virtio_net_hdr_ext); 759 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_MRG_RXBUF); 760 } 761 } 762 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_MAC)) 763 { 764 virtio_get_config( 765 &pContext->IODevice, 766 0, // + offsetof(struct virtio_net_config, mac) 767 &pContext->PermanentMacAddress, 768 ETH_LENGTH_OF_ADDRESS); 769 if (!ParaNdis_ValidateMacAddress(pContext->PermanentMacAddress, FALSE)) 770 { 771 DPrintf(0,("Invalid device MAC ignored(%02x-%02x-%02x-%02x-%02x-%02x)", 772 pContext->PermanentMacAddress[0], 773 pContext->PermanentMacAddress[1], 774 pContext->PermanentMacAddress[2], 775 pContext->PermanentMacAddress[3], 776 pContext->PermanentMacAddress[4], 777 pContext->PermanentMacAddress[5])); 778 NdisZeroMemory(pContext->PermanentMacAddress, sizeof(pContext->PermanentMacAddress)); 779 } 780 } 781 782 if (ETH_IS_EMPTY(pContext->PermanentMacAddress)) 783 { 784 DPrintf(0, ("No device MAC present, use default")); 785 pContext->PermanentMacAddress[0] = 0x02; 786 pContext->PermanentMacAddress[1] = 0x50; 787 pContext->PermanentMacAddress[2] = 0xF2; 788 pContext->PermanentMacAddress[3] = 0x00; 789 pContext->PermanentMacAddress[4] = 0x01; 790 pContext->PermanentMacAddress[5] = 0x80 | (UCHAR)(pContext->ulUniqueID & 0xFF); 791 } 792 DPrintf(0,("Device MAC = %02x-%02x-%02x-%02x-%02x-%02x", 793 pContext->PermanentMacAddress[0], 794 pContext->PermanentMacAddress[1], 795 pContext->PermanentMacAddress[2], 796 pContext->PermanentMacAddress[3], 797 pContext->PermanentMacAddress[4], 798 pContext->PermanentMacAddress[5])); 799 800 if (ETH_IS_EMPTY(pContext->CurrentMacAddress)) 801 { 802 NdisMoveMemory( 803 &pContext->CurrentMacAddress, 804 &pContext->PermanentMacAddress, 805 ETH_LENGTH_OF_ADDRESS); 806 } 807 else 808 { 809 DPrintf(0,("Current MAC = %02x-%02x-%02x-%02x-%02x-%02x", 810 pContext->CurrentMacAddress[0], 811 pContext->CurrentMacAddress[1], 812 pContext->CurrentMacAddress[2], 813 pContext->CurrentMacAddress[3], 814 pContext->CurrentMacAddress[4], 815 pContext->CurrentMacAddress[5])); 816 } 817 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_CTRL_VQ)) { 818 pContext->bHasControlQueue = TRUE; 819 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_CTRL_VQ); 820 } 821 } 822 else 823 { 824 DPrintf(0, ("[%s] Error: Incomplete resources", __FUNCTION__)); 825 status = NDIS_STATUS_RESOURCE_CONFLICT; 826 } 827 828 829 if (pContext->bDoHardwareChecksum) 830 { 831 ULONG dependentOptions; 832 dependentOptions = osbT4TcpChecksum | osbT4UdpChecksum | osbT4TcpOptionsChecksum; 833 if (!VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_CSUM) && 834 (pContext->Offload.flagsValue & dependentOptions)) 835 { 836 DPrintf(0, ("[%s] Host does not support CSUM, disabling CS offload", __FUNCTION__) ); 837 pContext->Offload.flagsValue &= ~dependentOptions; 838 } 839 } 840 841 if (pContext->bDoGuestChecksumOnReceive && VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_GUEST_CSUM)) 842 { 843 DPrintf(0, ("[%s] Enabling guest checksum", __FUNCTION__) ); 844 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_GUEST_CSUM); 845 } 846 else 847 { 848 pContext->bDoGuestChecksumOnReceive = FALSE; 849 } 850 851 // now, after we checked the capabilities, we can initialize current 852 // configuration of offload tasks 853 ParaNdis_ResetOffloadSettings(pContext, NULL, NULL); 854 if (pContext->Offload.flags.fTxLso && !pContext->bUseScatterGather) 855 { 856 DisableBothLSOPermanently(pContext, __FUNCTION__, "SG is not active"); 857 } 858 if (pContext->Offload.flags.fTxLso && 859 !VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_HOST_TSO4)) 860 { 861 DisableLSOv4Permanently(pContext, __FUNCTION__, "Host does not support TSOv4"); 862 } 863 if (pContext->Offload.flags.fTxLsov6 && 864 !VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_HOST_TSO6)) 865 { 866 DisableLSOv6Permanently(pContext, __FUNCTION__, "Host does not support TSOv6"); 867 } 868 if (pContext->bUseIndirect) 869 { 870 const char *reason = ""; 871 if (!VirtIODeviceGetHostFeature(pContext, VIRTIO_RING_F_INDIRECT_DESC)) 872 { 873 pContext->bUseIndirect = FALSE; 874 reason = "Host support"; 875 } 876 else if (!pContext->bUseScatterGather) 877 { 878 pContext->bUseIndirect = FALSE; 879 reason = "SG"; 880 } 881 DPrintf(0, ("[%s] %sable indirect Tx(!%s)", __FUNCTION__, pContext->bUseIndirect ? "En" : "Dis", reason) ); 882 } 883 884 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_NET_F_CTRL_RX_EXTRA) && 885 pContext->bDoHwPacketFiltering) 886 { 887 DPrintf(0, ("[%s] Using hardware packet filtering", __FUNCTION__)); 888 pContext->bHasHardwareFilters = TRUE; 889 } 890 891 status = FinalizeFeatures(pContext); 892 893 pContext->ReuseBufferProc = (tReuseReceiveBufferProc)ReuseReceiveBufferRegular; 894 895 NdisInitializeEvent(&pContext->ResetEvent); 896 DEBUG_EXIT_STATUS(0, status); 897 return status; 898 } 899 900 /********************************************************** 901 Free the resources allocated for VirtIO buffer descriptor 902 Parameters: 903 PVOID pParam pIONetDescriptor to free 904 BOOLEAN bRemoveFromList TRUE, if also remove it from list 905 ***********************************************************/ 906 static void VirtIONetFreeBufferDescriptor(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBufferDescriptor) 907 { 908 if(pBufferDescriptor) 909 { 910 if (pBufferDescriptor->pHolder) 911 ParaNdis_UnbindBufferFromPacket(pContext, pBufferDescriptor); 912 if (pBufferDescriptor->DataInfo.Virtual) 913 ParaNdis_FreePhysicalMemory(pContext, &pBufferDescriptor->DataInfo); 914 if (pBufferDescriptor->HeaderInfo.Virtual) 915 ParaNdis_FreePhysicalMemory(pContext, &pBufferDescriptor->HeaderInfo); 916 NdisFreeMemory(pBufferDescriptor, 0, 0); 917 } 918 } 919 920 /********************************************************** 921 Free all the buffer descriptors from specified list 922 Parameters: 923 PLIST_ENTRY pListRoot list containing pIONetDescriptor structures 924 PNDIS_SPIN_LOCK pLock lock to protest this list 925 Return value: 926 ***********************************************************/ 927 static void FreeDescriptorsFromList(PARANDIS_ADAPTER *pContext, PLIST_ENTRY pListRoot, PNDIS_SPIN_LOCK pLock) 928 { 929 pIONetDescriptor pBufferDescriptor; 930 LIST_ENTRY TempList; 931 InitializeListHead(&TempList); 932 NdisAcquireSpinLock(pLock); 933 while(!IsListEmpty(pListRoot)) 934 { 935 pBufferDescriptor = (pIONetDescriptor)RemoveHeadList(pListRoot); 936 InsertTailList(&TempList, &pBufferDescriptor->listEntry); 937 } 938 NdisReleaseSpinLock(pLock); 939 while(!IsListEmpty(&TempList)) 940 { 941 pBufferDescriptor = (pIONetDescriptor)RemoveHeadList(&TempList); 942 VirtIONetFreeBufferDescriptor(pContext, pBufferDescriptor); 943 } 944 } 945 946 static pIONetDescriptor AllocatePairOfBuffersOnInit( 947 PARANDIS_ADAPTER *pContext, 948 ULONG size1, 949 ULONG size2, 950 BOOLEAN bForTx) 951 { 952 pIONetDescriptor p; 953 p = (pIONetDescriptor)ParaNdis_AllocateMemory(pContext, sizeof(*p)); 954 if (p) 955 { 956 BOOLEAN b1 = FALSE, b2 = FALSE; 957 NdisZeroMemory(p, sizeof(*p)); 958 p->HeaderInfo.size = size1; 959 p->DataInfo.size = size2; 960 p->HeaderInfo.IsCached = p->DataInfo.IsCached = 1; 961 p->HeaderInfo.IsTX = p->DataInfo.IsTX = bForTx; 962 p->nofUsedBuffers = 0; 963 b1 = ParaNdis_InitialAllocatePhysicalMemory(pContext, &p->HeaderInfo); 964 if (b1) b2 = ParaNdis_InitialAllocatePhysicalMemory(pContext, &p->DataInfo); 965 if (b1 && b2) 966 { 967 BOOLEAN b = bForTx || ParaNdis_BindBufferToPacket(pContext, p); 968 if (!b) 969 { 970 DPrintf(0, ("[INITPHYS](%s) Failed to bind memory to net packet", bForTx ? "TX" : "RX")); 971 VirtIONetFreeBufferDescriptor(pContext, p); 972 p = NULL; 973 } 974 } 975 else 976 { 977 if (b1) ParaNdis_FreePhysicalMemory(pContext, &p->HeaderInfo); 978 if (b2) ParaNdis_FreePhysicalMemory(pContext, &p->DataInfo); 979 NdisFreeMemory(p, 0, 0); 980 p = NULL; 981 DPrintf(0, ("[INITPHYS](%s) Failed to allocate memory block", bForTx ? "TX" : "RX")); 982 } 983 } 984 if (p) 985 { 986 DPrintf(3, ("[INITPHYS](%s) Header v%p(p%08lX), Data v%p(p%08lX)", bForTx ? "TX" : "RX", 987 p->HeaderInfo.Virtual, p->HeaderInfo.Physical.LowPart, 988 p->DataInfo.Virtual, p->DataInfo.Physical.LowPart)); 989 } 990 return p; 991 } 992 993 /********************************************************** 994 Allocates TX buffers according to startup setting (pContext->maxFreeTxDescriptors as got from registry) 995 Buffers are chained in NetFreeSendBuffers 996 Parameters: 997 context 998 ***********************************************************/ 999 static void PrepareTransmitBuffers(PARANDIS_ADAPTER *pContext) 1000 { 1001 UINT nBuffers, nMaxBuffers; 1002 DEBUG_ENTRY(4); 1003 nMaxBuffers = virtio_get_queue_size(pContext->NetSendQueue) / 2; 1004 if (nMaxBuffers > pContext->maxFreeTxDescriptors) nMaxBuffers = pContext->maxFreeTxDescriptors; 1005 1006 for (nBuffers = 0; nBuffers < nMaxBuffers; ++nBuffers) 1007 { 1008 pIONetDescriptor pBuffersDescriptor = 1009 AllocatePairOfBuffersOnInit( 1010 pContext, 1011 pContext->nVirtioHeaderSize, 1012 pContext->MaxPacketSize.nMaxFullSizeHwTx, 1013 TRUE); 1014 if (!pBuffersDescriptor) break; 1015 1016 NdisZeroMemory(pBuffersDescriptor->HeaderInfo.Virtual, pBuffersDescriptor->HeaderInfo.size); 1017 InsertTailList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry); 1018 pContext->nofFreeTxDescriptors++; 1019 } 1020 1021 pContext->maxFreeTxDescriptors = pContext->nofFreeTxDescriptors; 1022 pContext->nofFreeHardwareBuffers = pContext->nofFreeTxDescriptors * 2; 1023 pContext->maxFreeHardwareBuffers = pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers; 1024 DPrintf(0, ("[%s] available %d Tx descriptors, %d hw buffers", 1025 __FUNCTION__, pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers)); 1026 } 1027 1028 static BOOLEAN AddRxBufferToQueue(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBufferDescriptor) 1029 { 1030 UINT nBuffersToSubmit = 2; 1031 struct VirtIOBufferDescriptor sg[2]; 1032 if (!pContext->bUseMergedBuffers) 1033 { 1034 sg[0].physAddr = pBufferDescriptor->HeaderInfo.Physical; 1035 sg[0].length = pBufferDescriptor->HeaderInfo.size; 1036 sg[1].physAddr = pBufferDescriptor->DataInfo.Physical; 1037 sg[1].length = pBufferDescriptor->DataInfo.size; 1038 } 1039 else 1040 { 1041 sg[0].physAddr = pBufferDescriptor->DataInfo.Physical; 1042 sg[0].length = pBufferDescriptor->DataInfo.size; 1043 nBuffersToSubmit = 1; 1044 } 1045 return 0 <= virtqueue_add_buf( 1046 pContext->NetReceiveQueue, 1047 sg, 1048 0, 1049 nBuffersToSubmit, 1050 pBufferDescriptor, 1051 NULL, 1052 0); 1053 } 1054 1055 1056 /********************************************************** 1057 Allocates maximum RX buffers for incoming packets 1058 Buffers are chained in NetReceiveBuffers 1059 Parameters: 1060 context 1061 ***********************************************************/ 1062 static int PrepareReceiveBuffers(PARANDIS_ADAPTER *pContext) 1063 { 1064 int nRet = 0; 1065 UINT i; 1066 DEBUG_ENTRY(4); 1067 1068 for (i = 0; i < pContext->NetMaxReceiveBuffers; ++i) 1069 { 1070 ULONG size1 = pContext->bUseMergedBuffers ? 4 : pContext->nVirtioHeaderSize; 1071 ULONG size2 = pContext->MaxPacketSize.nMaxFullSizeHwRx + 1072 (pContext->bUseMergedBuffers ? pContext->nVirtioHeaderSize : 0); 1073 pIONetDescriptor pBuffersDescriptor = 1074 AllocatePairOfBuffersOnInit(pContext, size1, size2, FALSE); 1075 if (!pBuffersDescriptor) break; 1076 1077 if (!AddRxBufferToQueue(pContext, pBuffersDescriptor)) 1078 { 1079 VirtIONetFreeBufferDescriptor(pContext, pBuffersDescriptor); 1080 break; 1081 } 1082 1083 InsertTailList(&pContext->NetReceiveBuffers, &pBuffersDescriptor->listEntry); 1084 1085 pContext->NetNofReceiveBuffers++; 1086 } 1087 1088 pContext->NetMaxReceiveBuffers = pContext->NetNofReceiveBuffers; 1089 DPrintf(0, ("[%s] MaxReceiveBuffers %d\n", __FUNCTION__, pContext->NetMaxReceiveBuffers) ); 1090 1091 virtqueue_kick(pContext->NetReceiveQueue); 1092 1093 return nRet; 1094 } 1095 1096 static NDIS_STATUS FindNetQueues(PARANDIS_ADAPTER *pContext) 1097 { 1098 struct virtqueue *queues[3]; 1099 unsigned nvqs = pContext->bHasControlQueue ? 3 : 2; 1100 NTSTATUS status; 1101 1102 // We work with two or three virtqueues, 0 - receive, 1 - send, 2 - control 1103 status = virtio_find_queues( 1104 &pContext->IODevice, 1105 nvqs, 1106 queues); 1107 if (!NT_SUCCESS(status)) { 1108 DPrintf(0, ("[%s] virtio_find_queues failed with %x\n", __FUNCTION__, status)); 1109 return NTStatusToNdisStatus(status); 1110 } 1111 1112 pContext->NetReceiveQueue = queues[0]; 1113 pContext->NetSendQueue = queues[1]; 1114 if (pContext->bHasControlQueue) { 1115 pContext->NetControlQueue = queues[2]; 1116 } 1117 1118 return NDIS_STATUS_SUCCESS; 1119 } 1120 1121 // called on PASSIVE upon unsuccessful Init or upon Halt 1122 static void DeleteNetQueues(PARANDIS_ADAPTER *pContext) 1123 { 1124 virtio_delete_queues(&pContext->IODevice); 1125 } 1126 1127 /********************************************************** 1128 Initializes VirtIO buffering and related stuff: 1129 Allocates RX and TX queues and buffers 1130 Parameters: 1131 context 1132 Return value: 1133 TRUE if both queues are allocated 1134 ***********************************************************/ 1135 static NDIS_STATUS ParaNdis_VirtIONetInit(PARANDIS_ADAPTER *pContext) 1136 { 1137 NDIS_STATUS status; 1138 DEBUG_ENTRY(0); 1139 1140 pContext->ControlData.IsCached = 1; 1141 pContext->ControlData.size = 512; 1142 1143 status = FindNetQueues(pContext); 1144 if (status != NDIS_STATUS_SUCCESS) { 1145 return status; 1146 } 1147 1148 if (pContext->NetReceiveQueue && pContext->NetSendQueue) 1149 { 1150 PrepareTransmitBuffers(pContext); 1151 PrepareReceiveBuffers(pContext); 1152 1153 if (pContext->NetControlQueue) 1154 ParaNdis_InitialAllocatePhysicalMemory(pContext, &pContext->ControlData); 1155 if (!pContext->NetControlQueue || !pContext->ControlData.Virtual) 1156 { 1157 DPrintf(0, ("[%s] The Control vQueue does not work!\n", __FUNCTION__) ); 1158 pContext->bHasHardwareFilters = FALSE; 1159 } 1160 if (pContext->nofFreeTxDescriptors && 1161 pContext->NetMaxReceiveBuffers && 1162 pContext->maxFreeHardwareBuffers) 1163 { 1164 pContext->sgTxGatherTable = ParaNdis_AllocateMemory(pContext, 1165 pContext->maxFreeHardwareBuffers * sizeof(pContext->sgTxGatherTable[0])); 1166 if (!pContext->sgTxGatherTable) 1167 { 1168 DisableBothLSOPermanently(pContext, __FUNCTION__, "Can not allocate SG table"); 1169 } 1170 status = NDIS_STATUS_SUCCESS; 1171 } 1172 } 1173 else 1174 { 1175 DeleteNetQueues(pContext); 1176 status = NDIS_STATUS_RESOURCES; 1177 } 1178 return status; 1179 } 1180 1181 static void VirtIODeviceRemoveStatus(VirtIODevice *vdev, u8 status) 1182 { 1183 virtio_set_status( 1184 vdev, 1185 virtio_get_status(vdev) & ~status); 1186 } 1187 1188 /********************************************************** 1189 Finishes initialization of context structure, calling also version dependent part 1190 If this procedure failed, ParaNdis_CleanupContext must be called 1191 Parameters: 1192 context 1193 Return value: 1194 SUCCESS or some kind of failure 1195 ***********************************************************/ 1196 NDIS_STATUS ParaNdis_FinishInitialization(PARANDIS_ADAPTER *pContext) 1197 { 1198 NDIS_STATUS status = NDIS_STATUS_SUCCESS; 1199 DEBUG_ENTRY(0); 1200 1201 NdisAllocateSpinLock(&pContext->SendLock); 1202 #if !defined(UNIFY_LOCKS) 1203 NdisAllocateSpinLock(&pContext->ReceiveLock); 1204 #endif 1205 1206 InitializeListHead(&pContext->NetReceiveBuffers); 1207 InitializeListHead(&pContext->NetReceiveBuffersWaiting); 1208 InitializeListHead(&pContext->NetSendBuffersInUse); 1209 InitializeListHead(&pContext->NetFreeSendBuffers); 1210 1211 status = ParaNdis_FinishSpecificInitialization(pContext); 1212 1213 if (status == NDIS_STATUS_SUCCESS) 1214 { 1215 status = ParaNdis_VirtIONetInit(pContext); 1216 } 1217 1218 pContext->Limits.nReusedRxBuffers = pContext->NetMaxReceiveBuffers / 4 + 1; 1219 1220 if (status == NDIS_STATUS_SUCCESS) 1221 { 1222 JustForCheckClearInterrupt(pContext, "start 3"); 1223 pContext->bEnableInterruptHandlingDPC = TRUE; 1224 ParaNdis_SetPowerState(pContext, NdisDeviceStateD0); 1225 virtio_device_ready(&pContext->IODevice); 1226 JustForCheckClearInterrupt(pContext, "start 4"); 1227 ParaNdis_UpdateDeviceFilters(pContext); 1228 } 1229 else 1230 { 1231 virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_FAILED); 1232 } 1233 DEBUG_EXIT_STATUS(0, status); 1234 return status; 1235 } 1236 1237 /********************************************************** 1238 Releases VirtIO related resources - queues and buffers 1239 Parameters: 1240 context 1241 Return value: 1242 ***********************************************************/ 1243 static void VirtIONetRelease(PARANDIS_ADAPTER *pContext) 1244 { 1245 BOOLEAN b; 1246 DEBUG_ENTRY(0); 1247 1248 /* list NetReceiveBuffersWaiting must be free */ 1249 do 1250 { 1251 NdisAcquireSpinLock(&pContext->ReceiveLock); 1252 b = !IsListEmpty(&pContext->NetReceiveBuffersWaiting); 1253 NdisReleaseSpinLock(&pContext->ReceiveLock); 1254 if (b) 1255 { 1256 DPrintf(0, ("[%s] There are waiting buffers", __FUNCTION__)); 1257 PrintStatistics(pContext); 1258 NdisMSleep(5000000); 1259 } 1260 }while (b); 1261 1262 DeleteNetQueues(pContext); 1263 virtio_device_shutdown(&pContext->IODevice); 1264 pContext->bIODeviceInitialized = FALSE; 1265 1266 /* intentionally commented out 1267 FreeDescriptorsFromList( 1268 pContext, 1269 &pContext->NetReceiveBuffersWaiting, 1270 &pContext->ReceiveLock); 1271 */ 1272 1273 /* this can be freed, queue shut down */ 1274 FreeDescriptorsFromList( 1275 pContext, 1276 &pContext->NetReceiveBuffers, 1277 &pContext->ReceiveLock); 1278 1279 /* this can be freed, queue shut down */ 1280 FreeDescriptorsFromList( 1281 pContext, 1282 &pContext->NetSendBuffersInUse, 1283 &pContext->SendLock); 1284 1285 /* this can be freed, send disabled */ 1286 FreeDescriptorsFromList( 1287 pContext, 1288 &pContext->NetFreeSendBuffers, 1289 &pContext->SendLock); 1290 1291 if (pContext->ControlData.Virtual) 1292 ParaNdis_FreePhysicalMemory(pContext, &pContext->ControlData); 1293 1294 PrintStatistics(pContext); 1295 if (pContext->sgTxGatherTable) 1296 { 1297 NdisFreeMemory(pContext->sgTxGatherTable, 0, 0); 1298 } 1299 } 1300 1301 static void PreventDPCServicing(PARANDIS_ADAPTER *pContext) 1302 { 1303 LONG inside;; 1304 pContext->bEnableInterruptHandlingDPC = FALSE; 1305 do 1306 { 1307 inside = InterlockedIncrement(&pContext->counterDPCInside); 1308 InterlockedDecrement(&pContext->counterDPCInside); 1309 if (inside > 1) 1310 { 1311 DPrintf(0, ("[%s] waiting!", __FUNCTION__)); 1312 NdisMSleep(20000); 1313 } 1314 } while (inside > 1); 1315 } 1316 1317 /********************************************************** 1318 Frees all the resources allocated when the context initialized, 1319 calling also version-dependent part 1320 Parameters: 1321 context 1322 ***********************************************************/ 1323 VOID ParaNdis_CleanupContext(PARANDIS_ADAPTER *pContext) 1324 { 1325 UINT i; 1326 1327 /* disable any interrupt generation */ 1328 if (pContext->IODevice.addr) 1329 { 1330 //int nActive; 1331 //nActive = virtio_read_isr_status(&pContext->IODevice); 1332 /* back compat - remove the OK flag only in legacy mode */ 1333 VirtIODeviceRemoveStatus(&pContext->IODevice, VIRTIO_CONFIG_S_DRIVER_OK); 1334 JustForCheckClearInterrupt(pContext, "exit 1"); 1335 //nActive += virtio_read_isr_status(&pContext->IODevice); 1336 //nActive += virtio_read_isr_status(&pContext->IODevice); 1337 //DPrintf(0, ("cleanup %d", nActive)); 1338 } 1339 1340 PreventDPCServicing(pContext); 1341 1342 /**************************************** 1343 ensure all the incoming packets returned, 1344 free all the buffers and their descriptors 1345 *****************************************/ 1346 1347 if (pContext->bIODeviceInitialized) 1348 { 1349 JustForCheckClearInterrupt(pContext, "exit 2"); 1350 ParaNdis_ResetVirtIONetDevice(pContext); 1351 JustForCheckClearInterrupt(pContext, "exit 3"); 1352 } 1353 1354 ParaNdis_SetPowerState(pContext, NdisDeviceStateD3); 1355 VirtIONetRelease(pContext); 1356 1357 ParaNdis_FinalizeCleanup(pContext); 1358 1359 if (pContext->SendLock.SpinLock) 1360 { 1361 NdisFreeSpinLock(&pContext->SendLock); 1362 } 1363 1364 #if !defined(UNIFY_LOCKS) 1365 if (pContext->ReceiveLock.SpinLock) 1366 { 1367 NdisFreeSpinLock(&pContext->ReceiveLock); 1368 } 1369 #endif 1370 1371 /* free queue shared memory */ 1372 for (i = 0; i < MAX_NUM_OF_QUEUES; i++) { 1373 if (pContext->SharedMemoryRanges[i].pBase != NULL) { 1374 NdisMFreeSharedMemory( 1375 pContext->MiniportHandle, 1376 pContext->SharedMemoryRanges[i].uLength, 1377 TRUE /* Cached */, 1378 pContext->SharedMemoryRanges[i].pBase, 1379 pContext->SharedMemoryRanges[i].BasePA); 1380 pContext->SharedMemoryRanges[i].pBase = NULL; 1381 } 1382 } 1383 1384 /* unmap our port and memory IO resources */ 1385 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) 1386 { 1387 tBusResource *pRes = &pContext->AdapterResources.PciBars[i]; 1388 if (pRes->pBase != NULL) 1389 { 1390 if (pRes->bPortSpace) 1391 { 1392 NdisMDeregisterIoPortRange( 1393 pContext->MiniportHandle, 1394 pRes->BasePA.LowPart, 1395 pRes->uLength, 1396 pRes->pBase); 1397 } 1398 else 1399 { 1400 NdisMUnmapIoSpace( 1401 pContext->MiniportHandle, 1402 pRes->pBase, 1403 pRes->uLength); 1404 } 1405 } 1406 } 1407 } 1408 1409 1410 /********************************************************** 1411 System shutdown handler (shutdown, restart, bugcheck) 1412 Parameters: 1413 context 1414 ***********************************************************/ 1415 VOID ParaNdis_OnShutdown(PARANDIS_ADAPTER *pContext) 1416 { 1417 DEBUG_ENTRY(0); // this is only for kdbg :) 1418 ParaNdis_ResetVirtIONetDevice(pContext); 1419 } 1420 1421 /********************************************************** 1422 Handles hardware interrupt 1423 Parameters: 1424 context 1425 ULONG knownInterruptSources - bitmask of 1426 Return value: 1427 TRUE, if it is our interrupt 1428 sets *pRunDpc to TRUE if the DPC should be fired 1429 ***********************************************************/ 1430 BOOLEAN ParaNdis_OnLegacyInterrupt( 1431 PARANDIS_ADAPTER *pContext, 1432 OUT BOOLEAN *pRunDpc) 1433 { 1434 ULONG status = virtio_read_isr_status(&pContext->IODevice); 1435 1436 if((status == 0) || 1437 (status == VIRTIO_NET_INVALID_INTERRUPT_STATUS) || 1438 (pContext->powerState != NdisDeviceStateD0)) 1439 { 1440 *pRunDpc = FALSE; 1441 return FALSE; 1442 } 1443 1444 PARANDIS_STORE_LAST_INTERRUPT_TIMESTAMP(pContext); 1445 ParaNdis_VirtIODisableIrqSynchronized(pContext, isAny); 1446 InterlockedOr(&pContext->InterruptStatus, (LONG) ((status & isControl) | isReceive | isTransmit)); 1447 *pRunDpc = TRUE; 1448 return TRUE; 1449 } 1450 1451 BOOLEAN ParaNdis_OnQueuedInterrupt( 1452 PARANDIS_ADAPTER *pContext, 1453 OUT BOOLEAN *pRunDpc, 1454 ULONG knownInterruptSources) 1455 { 1456 struct virtqueue* _vq = ParaNdis_GetQueueForInterrupt(pContext, knownInterruptSources); 1457 1458 /* If interrupts for this queue disabled do nothing */ 1459 if((_vq != NULL) && !ParaNDIS_IsQueueInterruptEnabled(_vq)) 1460 { 1461 *pRunDpc = FALSE; 1462 } 1463 else 1464 { 1465 PARANDIS_STORE_LAST_INTERRUPT_TIMESTAMP(pContext); 1466 InterlockedOr(&pContext->InterruptStatus, (LONG)knownInterruptSources); 1467 ParaNdis_VirtIODisableIrqSynchronized(pContext, knownInterruptSources); 1468 *pRunDpc = TRUE; 1469 } 1470 1471 return *pRunDpc; 1472 } 1473 1474 1475 /********************************************************** 1476 It is called from Rx processing routines in regular mode of operation. 1477 Returns received buffer back to VirtIO queue, inserting it to NetReceiveBuffers. 1478 If needed, signals end of RX pause operation 1479 1480 Must be called with &pContext->ReceiveLock acquired 1481 1482 Parameters: 1483 context 1484 void *pDescriptor - pIONetDescriptor to return 1485 ***********************************************************/ 1486 void ReuseReceiveBufferRegular(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor) 1487 { 1488 DEBUG_ENTRY(4); 1489 1490 if(!pBuffersDescriptor) 1491 return; 1492 1493 RemoveEntryList(&pBuffersDescriptor->listEntry); 1494 1495 if(AddRxBufferToQueue(pContext, pBuffersDescriptor)) 1496 { 1497 InsertTailList(&pContext->NetReceiveBuffers, &pBuffersDescriptor->listEntry); 1498 1499 pContext->NetNofReceiveBuffers++; 1500 1501 if (pContext->NetNofReceiveBuffers > pContext->NetMaxReceiveBuffers) 1502 { 1503 DPrintf(0, (" Error: NetNofReceiveBuffers > NetMaxReceiveBuffers(%d>%d)", 1504 pContext->NetNofReceiveBuffers, pContext->NetMaxReceiveBuffers)); 1505 } 1506 1507 if (++pContext->Counters.nReusedRxBuffers >= pContext->Limits.nReusedRxBuffers) 1508 { 1509 pContext->Counters.nReusedRxBuffers = 0; 1510 virtqueue_kick_always(pContext->NetReceiveQueue); 1511 } 1512 1513 if (IsListEmpty(&pContext->NetReceiveBuffersWaiting)) 1514 { 1515 if (pContext->ReceiveState == srsPausing || pContext->ReceivePauseCompletionProc) 1516 { 1517 ONPAUSECOMPLETEPROC callback = pContext->ReceivePauseCompletionProc; 1518 pContext->ReceiveState = srsDisabled; 1519 pContext->ReceivePauseCompletionProc = NULL; 1520 ParaNdis_DebugHistory(pContext, hopInternalReceivePause, NULL, 0, 0, 0); 1521 if (callback) callback(pContext); 1522 } 1523 } 1524 } 1525 else 1526 { 1527 DPrintf(0, ("FAILED TO REUSE THE BUFFER!!!!")); 1528 VirtIONetFreeBufferDescriptor(pContext, pBuffersDescriptor); 1529 pContext->NetMaxReceiveBuffers--; 1530 } 1531 } 1532 1533 /********************************************************** 1534 It is called from Rx processing routines between power off and power on in non-paused mode (Win8). 1535 Returns received buffer to NetReceiveBuffers. 1536 All the buffers will be placed into Virtio queue during power-on procedure 1537 1538 Must be called with &pContext->ReceiveLock acquired 1539 1540 Parameters: 1541 context 1542 void *pDescriptor - pIONetDescriptor to return 1543 ***********************************************************/ 1544 static void ReuseReceiveBufferPowerOff(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBuffersDescriptor) 1545 { 1546 RemoveEntryList(&pBuffersDescriptor->listEntry); 1547 InsertTailList(&pContext->NetReceiveBuffers, &pBuffersDescriptor->listEntry); 1548 } 1549 1550 /********************************************************** 1551 It is called from Tx processing routines 1552 Gets all the finished buffer from VirtIO TX path and 1553 returns them to NetFreeSendBuffers 1554 1555 Must be called with &pContext->SendLock acquired 1556 1557 Parameters: 1558 context 1559 Return value: 1560 (for reference) number of TX buffers returned 1561 ***********************************************************/ 1562 UINT ParaNdis_VirtIONetReleaseTransmitBuffers( 1563 PARANDIS_ADAPTER *pContext) 1564 { 1565 UINT len, i = 0; 1566 pIONetDescriptor pBufferDescriptor; 1567 1568 DEBUG_ENTRY(4); 1569 1570 while(NULL != (pBufferDescriptor = virtqueue_get_buf(pContext->NetSendQueue, &len))) 1571 { 1572 RemoveEntryList(&pBufferDescriptor->listEntry); 1573 pContext->nofFreeTxDescriptors++; 1574 if (!pBufferDescriptor->nofUsedBuffers) 1575 { 1576 DPrintf(0, ("[%s] ERROR: nofUsedBuffers not set!", __FUNCTION__)); 1577 } 1578 pContext->nofFreeHardwareBuffers += pBufferDescriptor->nofUsedBuffers; 1579 ParaNdis_OnTransmitBufferReleased(pContext, pBufferDescriptor); 1580 InsertTailList(&pContext->NetFreeSendBuffers, &pBufferDescriptor->listEntry); 1581 DPrintf(3, ("[%s] Free Tx: desc %d, buff %d", __FUNCTION__, pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers)); 1582 pBufferDescriptor->nofUsedBuffers = 0; 1583 ++i; 1584 } 1585 if (i) 1586 { 1587 NdisGetCurrentSystemTime(&pContext->LastTxCompletionTimeStamp); 1588 pContext->bDoKickOnNoBuffer = TRUE; 1589 pContext->nDetectedStoppedTx = 0; 1590 } 1591 DEBUG_EXIT_STATUS((i ? 3 : 5), i); 1592 return i; 1593 } 1594 1595 static ULONG FORCEINLINE QueryTcpHeaderOffset(PVOID packetData, ULONG ipHeaderOffset, ULONG ipPacketLength) 1596 { 1597 ULONG res; 1598 tTcpIpPacketParsingResult ppr = ParaNdis_ReviewIPPacket( 1599 (PUCHAR)packetData + ipHeaderOffset, 1600 ipPacketLength, 1601 __FUNCTION__); 1602 if (ppr.xxpStatus == ppresXxpKnown) 1603 { 1604 res = ipHeaderOffset + ppr.ipHeaderSize; 1605 } 1606 else 1607 { 1608 DPrintf(0, ("[%s] ERROR: NOT a TCP or UDP packet - expected troubles!", __FUNCTION__)); 1609 res = 0; 1610 } 1611 return res; 1612 } 1613 1614 1615 /********************************************************* 1616 Called with from ProcessTx routine with TxLock held 1617 Uses pContext->sgTxGatherTable 1618 ***********************************************************/ 1619 tCopyPacketResult ParaNdis_DoSubmitPacket(PARANDIS_ADAPTER *pContext, tTxOperationParameters *Params) 1620 { 1621 tCopyPacketResult result; 1622 tMapperResult mapResult = {0,0,0}; 1623 // populating priority tag or LSO MAY require additional SG element 1624 UINT nRequiredBuffers; 1625 BOOLEAN bUseCopy = FALSE; 1626 struct VirtIOBufferDescriptor *sg = pContext->sgTxGatherTable; 1627 1628 nRequiredBuffers = Params->nofSGFragments + 1 + ((Params->flags & (pcrPriorityTag | pcrLSO)) ? 1 : 0); 1629 1630 result.size = 0; 1631 result.error = cpeOK; 1632 if (!pContext->bUseScatterGather || // only copy available 1633 Params->nofSGFragments == 0 || // theoretical case 1634 !sg || // only copy available 1635 ((~Params->flags & pcrLSO) && nRequiredBuffers > pContext->maxFreeHardwareBuffers) // to many fragments and normal size of packet 1636 ) 1637 { 1638 nRequiredBuffers = 2; 1639 bUseCopy = TRUE; 1640 } 1641 else if (pContext->bUseIndirect && !(Params->flags & pcrNoIndirect)) 1642 { 1643 nRequiredBuffers = 1; 1644 } 1645 1646 // I do not think this will help, but at least we can try freeing some buffers right now 1647 if (pContext->nofFreeHardwareBuffers < nRequiredBuffers || !pContext->nofFreeTxDescriptors) 1648 { 1649 ParaNdis_VirtIONetReleaseTransmitBuffers(pContext); 1650 } 1651 1652 if (nRequiredBuffers > pContext->maxFreeHardwareBuffers) 1653 { 1654 // LSO and too many buffers, impossible to send 1655 result.error = cpeTooLarge; 1656 DPrintf(0, ("[%s] ERROR: too many fragments(%d required, %d max.avail)!", __FUNCTION__, 1657 nRequiredBuffers, pContext->maxFreeHardwareBuffers)); 1658 } 1659 else if (pContext->nofFreeHardwareBuffers < nRequiredBuffers || !pContext->nofFreeTxDescriptors) 1660 { 1661 virtqueue_enable_cb_delayed(pContext->NetSendQueue); 1662 result.error = cpeNoBuffer; 1663 } 1664 else if (Params->offloadMss && bUseCopy) 1665 { 1666 result.error = cpeInternalError; 1667 DPrintf(0, ("[%s] ERROR: expecting SG for TSO! (%d buffers, %d bytes)", __FUNCTION__, 1668 Params->nofSGFragments, Params->ulDataSize)); 1669 } 1670 else if (bUseCopy) 1671 { 1672 result = ParaNdis_DoCopyPacketData(pContext, Params); 1673 } 1674 else 1675 { 1676 UINT nMappedBuffers; 1677 ULONGLONG paOfIndirectArea = 0; 1678 PVOID vaOfIndirectArea = NULL; 1679 pIONetDescriptor pBuffersDescriptor = (pIONetDescriptor)RemoveHeadList(&pContext->NetFreeSendBuffers); 1680 pContext->nofFreeTxDescriptors--; 1681 NdisZeroMemory(pBuffersDescriptor->HeaderInfo.Virtual, pBuffersDescriptor->HeaderInfo.size); 1682 sg[0].physAddr = pBuffersDescriptor->HeaderInfo.Physical; 1683 sg[0].length = pBuffersDescriptor->HeaderInfo.size; 1684 ParaNdis_PacketMapper( 1685 pContext, 1686 Params->packet, 1687 Params->ReferenceValue, 1688 sg + 1, 1689 pBuffersDescriptor, 1690 &mapResult); 1691 nMappedBuffers = mapResult.usBuffersMapped; 1692 if (nMappedBuffers) 1693 { 1694 nMappedBuffers++; 1695 if (pContext->bUseIndirect && !(Params->flags & pcrNoIndirect)) 1696 { 1697 ULONG space1 = (mapResult.usBufferSpaceUsed + 7) & ~7; 1698 ULONG space2 = nMappedBuffers * SIZE_OF_SINGLE_INDIRECT_DESC; 1699 if (pBuffersDescriptor->DataInfo.size >= (space1 + space2)) 1700 { 1701 vaOfIndirectArea = RtlOffsetToPointer(pBuffersDescriptor->DataInfo.Virtual, space1); 1702 paOfIndirectArea = pBuffersDescriptor->DataInfo.Physical.QuadPart + space1; 1703 pContext->extraStatistics.framesIndirect++; 1704 } 1705 else if (nMappedBuffers <= pContext->nofFreeHardwareBuffers) 1706 { 1707 // send as is, no indirect 1708 } 1709 else 1710 { 1711 result.error = cpeNoIndirect; 1712 DPrintf(0, ("[%s] Unexpected ERROR of placement!", __FUNCTION__)); 1713 } 1714 } 1715 if (result.error == cpeOK) 1716 { 1717 if (Params->flags & (pcrTcpChecksum | pcrUdpChecksum)) 1718 { 1719 unsigned short addPriorityLen = (Params->flags & pcrPriorityTag) ? ETH_PRIORITY_HEADER_SIZE : 0; 1720 if (pContext->bDoHardwareChecksum) 1721 { 1722 virtio_net_hdr_basic *pheader = pBuffersDescriptor->HeaderInfo.Virtual; 1723 pheader->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 1724 if (!Params->tcpHeaderOffset) 1725 { 1726 Params->tcpHeaderOffset = QueryTcpHeaderOffset( 1727 pBuffersDescriptor->DataInfo.Virtual, 1728 pContext->Offload.ipHeaderOffset + addPriorityLen, 1729 mapResult.usBufferSpaceUsed - pContext->Offload.ipHeaderOffset - addPriorityLen); 1730 } 1731 else 1732 { 1733 Params->tcpHeaderOffset += addPriorityLen; 1734 } 1735 pheader->csum_start = (USHORT)Params->tcpHeaderOffset; 1736 pheader->csum_offset = (Params->flags & pcrTcpChecksum) ? TCP_CHECKSUM_OFFSET : UDP_CHECKSUM_OFFSET; 1737 } 1738 else 1739 { 1740 // emulation mode - it is slow and intended only for test of flows 1741 // and debugging of WLK test cases 1742 PVOID pCopy = ParaNdis_AllocateMemory(pContext, Params->ulDataSize); 1743 if (pCopy) 1744 { 1745 tTcpIpPacketParsingResult ppr; 1746 // duplicate entire packet 1747 ParaNdis_PacketCopier(Params->packet, pCopy, Params->ulDataSize, Params->ReferenceValue, FALSE); 1748 // calculate complete TCP/UDP checksum 1749 ppr = ParaNdis_CheckSumVerify( 1750 RtlOffsetToPointer(pCopy, pContext->Offload.ipHeaderOffset + addPriorityLen), 1751 Params->ulDataSize - pContext->Offload.ipHeaderOffset - addPriorityLen, 1752 pcrAnyChecksum | pcrFixXxpChecksum, 1753 __FUNCTION__); 1754 // data portion in aside buffer contains complete IP+TCP header 1755 // rewrite copy of original buffer by one new with calculated data 1756 NdisMoveMemory( 1757 pBuffersDescriptor->DataInfo.Virtual, 1758 pCopy, 1759 mapResult.usBufferSpaceUsed); 1760 NdisFreeMemory(pCopy, 0, 0); 1761 } 1762 } 1763 } 1764 1765 if (0 <= virtqueue_add_buf( 1766 pContext->NetSendQueue, 1767 sg, 1768 nMappedBuffers, 1769 0, 1770 pBuffersDescriptor, 1771 vaOfIndirectArea, 1772 paOfIndirectArea)) 1773 { 1774 pBuffersDescriptor->nofUsedBuffers = nMappedBuffers; 1775 pContext->nofFreeHardwareBuffers -= nMappedBuffers; 1776 if (pContext->minFreeHardwareBuffers > pContext->nofFreeHardwareBuffers) 1777 pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers; 1778 pBuffersDescriptor->ReferenceValue = Params->ReferenceValue; 1779 result.size = Params->ulDataSize; 1780 DPrintf(2, ("[%s] Submitted %d buffers (%d bytes), avail %d desc, %d bufs", 1781 __FUNCTION__, nMappedBuffers, result.size, 1782 pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers 1783 )); 1784 } 1785 else 1786 { 1787 result.error = cpeInternalError; 1788 DPrintf(0, ("[%s] Unexpected ERROR adding buffer to TX engine!..", __FUNCTION__)); 1789 } 1790 } 1791 } 1792 else 1793 { 1794 DPrintf(0, ("[%s] Unexpected ERROR: packet not mapped!", __FUNCTION__)); 1795 result.error = cpeInternalError; 1796 } 1797 1798 if (result.error == cpeOK) 1799 { 1800 UCHAR ethernetHeader[sizeof(ETH_HEADER)]; 1801 eInspectedPacketType packetType; 1802 /* get the ethernet header for review */ 1803 ParaNdis_PacketCopier(Params->packet, ethernetHeader, sizeof(ethernetHeader), Params->ReferenceValue, TRUE); 1804 packetType = QueryPacketType(ethernetHeader); 1805 DebugDumpPacket("sending", ethernetHeader, 3); 1806 InsertTailList(&pContext->NetSendBuffersInUse, &pBuffersDescriptor->listEntry); 1807 pContext->Statistics.ifHCOutOctets += result.size; 1808 switch (packetType) 1809 { 1810 case iptBroadcast: 1811 pContext->Statistics.ifHCOutBroadcastOctets += result.size; 1812 pContext->Statistics.ifHCOutBroadcastPkts++; 1813 break; 1814 case iptMulticast: 1815 pContext->Statistics.ifHCOutMulticastOctets += result.size; 1816 pContext->Statistics.ifHCOutMulticastPkts++; 1817 break; 1818 default: 1819 pContext->Statistics.ifHCOutUcastOctets += result.size; 1820 pContext->Statistics.ifHCOutUcastPkts++; 1821 break; 1822 } 1823 1824 if (Params->flags & pcrLSO) 1825 pContext->extraStatistics.framesLSO++; 1826 } 1827 else 1828 { 1829 pContext->nofFreeTxDescriptors++; 1830 InsertHeadList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry); 1831 } 1832 } 1833 if (result.error == cpeNoBuffer && pContext->bDoKickOnNoBuffer) 1834 { 1835 virtqueue_kick_always(pContext->NetSendQueue); 1836 pContext->bDoKickOnNoBuffer = FALSE; 1837 } 1838 if (result.error == cpeOK) 1839 { 1840 if (Params->flags & (pcrTcpChecksum | pcrUdpChecksum)) 1841 pContext->extraStatistics.framesCSOffload++; 1842 } 1843 return result; 1844 } 1845 1846 1847 /********************************************************** 1848 It is called from Tx processing routines 1849 Prepares the VirtIO buffer and copies to it the data from provided packet 1850 1851 Must be called with &pContext->SendLock acquired 1852 1853 Parameters: 1854 context 1855 tPacketType packet specific type is NDIS dependent 1856 tCopyPacketDataFunction PacketCopier procedure for NDIS-specific type of packet 1857 Return value: 1858 (for reference) number of TX buffers returned 1859 ***********************************************************/ 1860 tCopyPacketResult ParaNdis_DoCopyPacketData( 1861 PARANDIS_ADAPTER *pContext, 1862 tTxOperationParameters *pParams) 1863 { 1864 tCopyPacketResult result; 1865 tCopyPacketResult CopierResult; 1866 struct VirtIOBufferDescriptor sg[2]; 1867 pIONetDescriptor pBuffersDescriptor = NULL; 1868 ULONG flags = pParams->flags; 1869 UINT nRequiredHardwareBuffers = 2; 1870 result.size = 0; 1871 result.error = cpeOK; 1872 if (pContext->nofFreeHardwareBuffers < nRequiredHardwareBuffers || 1873 IsListEmpty(&pContext->NetFreeSendBuffers)) 1874 { 1875 result.error = cpeNoBuffer; 1876 } 1877 if(result.error == cpeOK) 1878 { 1879 pBuffersDescriptor = (pIONetDescriptor)RemoveHeadList(&pContext->NetFreeSendBuffers); 1880 NdisZeroMemory(pBuffersDescriptor->HeaderInfo.Virtual, pBuffersDescriptor->HeaderInfo.size); 1881 sg[0].physAddr = pBuffersDescriptor->HeaderInfo.Physical; 1882 sg[0].length = pBuffersDescriptor->HeaderInfo.size; 1883 sg[1].physAddr = pBuffersDescriptor->DataInfo.Physical; 1884 CopierResult = ParaNdis_PacketCopier( 1885 pParams->packet, 1886 pBuffersDescriptor->DataInfo.Virtual, 1887 pBuffersDescriptor->DataInfo.size, 1888 pParams->ReferenceValue, 1889 FALSE); 1890 sg[1].length = result.size = CopierResult.size; 1891 // did NDIS ask us to compute CS? 1892 if ((flags & (pcrTcpChecksum | pcrUdpChecksum | pcrIpChecksum)) != 0) 1893 { 1894 // we asked 1895 unsigned short addPriorityLen = (pParams->flags & pcrPriorityTag) ? ETH_PRIORITY_HEADER_SIZE : 0; 1896 PVOID ipPacket = RtlOffsetToPointer( 1897 pBuffersDescriptor->DataInfo.Virtual, pContext->Offload.ipHeaderOffset + addPriorityLen); 1898 ULONG ipPacketLength = CopierResult.size - pContext->Offload.ipHeaderOffset - addPriorityLen; 1899 if (!pParams->tcpHeaderOffset && 1900 (flags & (pcrTcpChecksum | pcrUdpChecksum)) ) 1901 { 1902 pParams->tcpHeaderOffset = QueryTcpHeaderOffset( 1903 pBuffersDescriptor->DataInfo.Virtual, 1904 pContext->Offload.ipHeaderOffset + addPriorityLen, 1905 ipPacketLength); 1906 } 1907 else 1908 { 1909 pParams->tcpHeaderOffset += addPriorityLen; 1910 } 1911 1912 if (pContext->bDoHardwareChecksum) 1913 { 1914 if (flags & (pcrTcpChecksum | pcrUdpChecksum)) 1915 { 1916 // hardware offload 1917 virtio_net_hdr_basic *pvnh = (virtio_net_hdr_basic *)pBuffersDescriptor->HeaderInfo.Virtual; 1918 pvnh->csum_start = (USHORT)pParams->tcpHeaderOffset; 1919 pvnh->csum_offset = (flags & pcrTcpChecksum) ? TCP_CHECKSUM_OFFSET : UDP_CHECKSUM_OFFSET; 1920 pvnh->flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM; 1921 } 1922 if (flags & (pcrIpChecksum)) 1923 { 1924 ParaNdis_CheckSumVerify( 1925 ipPacket, 1926 ipPacketLength, 1927 pcrIpChecksum | pcrFixIPChecksum, 1928 __FUNCTION__); 1929 } 1930 } 1931 else if (CopierResult.size > pContext->Offload.ipHeaderOffset) 1932 { 1933 ULONG csFlags = 0; 1934 if (flags & pcrIpChecksum) csFlags |= pcrIpChecksum | pcrFixIPChecksum; 1935 if (flags & (pcrTcpChecksum | pcrUdpChecksum)) csFlags |= pcrTcpChecksum | pcrUdpChecksum| pcrFixXxpChecksum; 1936 // software offload 1937 ParaNdis_CheckSumVerify( 1938 ipPacket, 1939 ipPacketLength, 1940 csFlags, 1941 __FUNCTION__); 1942 } 1943 else 1944 { 1945 DPrintf(0, ("[%s] ERROR: Invalid buffer size for offload!", __FUNCTION__)); 1946 result.size = 0; 1947 result.error = cpeInternalError; 1948 } 1949 } 1950 pContext->nofFreeTxDescriptors--; 1951 if (result.size) 1952 { 1953 eInspectedPacketType packetType; 1954 packetType = QueryPacketType(pBuffersDescriptor->DataInfo.Virtual); 1955 DebugDumpPacket("sending", pBuffersDescriptor->DataInfo.Virtual, 3); 1956 1957 pBuffersDescriptor->nofUsedBuffers = nRequiredHardwareBuffers; 1958 pContext->nofFreeHardwareBuffers -= nRequiredHardwareBuffers; 1959 if (pContext->minFreeHardwareBuffers > pContext->nofFreeHardwareBuffers) 1960 pContext->minFreeHardwareBuffers = pContext->nofFreeHardwareBuffers; 1961 if (0 > virtqueue_add_buf( 1962 pContext->NetSendQueue, 1963 sg, 1964 2, 1965 0, 1966 pBuffersDescriptor, 1967 NULL, 1968 0 1969 )) 1970 { 1971 pBuffersDescriptor->nofUsedBuffers = 0; 1972 pContext->nofFreeHardwareBuffers += nRequiredHardwareBuffers; 1973 result.error = cpeInternalError; 1974 result.size = 0; 1975 DPrintf(0, ("[%s] Unexpected ERROR adding buffer to TX engine!..", __FUNCTION__)); 1976 } 1977 else 1978 { 1979 DPrintf(2, ("[%s] Submitted %d buffers (%d bytes), avail %d desc, %d bufs", 1980 __FUNCTION__, nRequiredHardwareBuffers, result.size, 1981 pContext->nofFreeTxDescriptors, pContext->nofFreeHardwareBuffers 1982 )); 1983 } 1984 if (result.error != cpeOK) 1985 { 1986 InsertTailList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry); 1987 pContext->nofFreeTxDescriptors++; 1988 } 1989 else 1990 { 1991 ULONG reportedSize = pParams->ulDataSize; 1992 pBuffersDescriptor->ReferenceValue = pParams->ReferenceValue; 1993 InsertTailList(&pContext->NetSendBuffersInUse, &pBuffersDescriptor->listEntry); 1994 pContext->Statistics.ifHCOutOctets += reportedSize; 1995 switch (packetType) 1996 { 1997 case iptBroadcast: 1998 pContext->Statistics.ifHCOutBroadcastOctets += reportedSize; 1999 pContext->Statistics.ifHCOutBroadcastPkts++; 2000 break; 2001 case iptMulticast: 2002 pContext->Statistics.ifHCOutMulticastOctets += reportedSize; 2003 pContext->Statistics.ifHCOutMulticastPkts++; 2004 break; 2005 default: 2006 pContext->Statistics.ifHCOutUcastOctets += reportedSize; 2007 pContext->Statistics.ifHCOutUcastPkts++; 2008 break; 2009 } 2010 } 2011 } 2012 else 2013 { 2014 DPrintf(0, ("[%s] Unexpected ERROR in copying packet data! Continue...", __FUNCTION__)); 2015 InsertTailList(&pContext->NetFreeSendBuffers, &pBuffersDescriptor->listEntry); 2016 pContext->nofFreeTxDescriptors++; 2017 // the buffer is not copied and the callback will not be called 2018 result.error = cpeInternalError; 2019 } 2020 } 2021 2022 return result; 2023 } 2024 2025 static ULONG ShallPassPacket(PARANDIS_ADAPTER *pContext, PVOID address, UINT len, eInspectedPacketType *pType) 2026 { 2027 ULONG b; 2028 if (len <= sizeof(ETH_HEADER)) return FALSE; 2029 if (len > pContext->MaxPacketSize.nMaxFullSizeHwRx) return FALSE; 2030 if (len > pContext->MaxPacketSize.nMaxFullSizeOS && !ETH_HAS_PRIO_HEADER(address)) return FALSE; 2031 *pType = QueryPacketType(address); 2032 if (pContext->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) return TRUE; 2033 2034 switch(*pType) 2035 { 2036 case iptBroadcast: 2037 b = pContext->PacketFilter & NDIS_PACKET_TYPE_BROADCAST; 2038 break; 2039 case iptMulticast: 2040 b = pContext->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST; 2041 if (!b && (pContext->PacketFilter & NDIS_PACKET_TYPE_MULTICAST)) 2042 { 2043 UINT i, n = pContext->MulticastData.nofMulticastEntries * ETH_LENGTH_OF_ADDRESS; 2044 b = 1; 2045 for (i = 0; b && i < n; i += ETH_LENGTH_OF_ADDRESS) 2046 { 2047 ETH_COMPARE_NETWORK_ADDRESSES((PUCHAR)address, &pContext->MulticastData.MulticastList[i], &b) 2048 } 2049 b = !b; 2050 } 2051 break; 2052 default: 2053 ETH_COMPARE_NETWORK_ADDRESSES((PUCHAR)address, pContext->CurrentMacAddress, &b); 2054 b = !b && (pContext->PacketFilter & NDIS_PACKET_TYPE_DIRECTED); 2055 break; 2056 } 2057 if (!b) 2058 { 2059 pContext->extraStatistics.framesFilteredOut++; 2060 } 2061 return b; 2062 } 2063 2064 void 2065 ParaNdis_PadPacketReceived(PVOID pDataBuffer, PULONG pLength) 2066 { 2067 // Ethernet standard declares minimal possible packet size 2068 // Packets smaller than that must be padded before transfer 2069 // Ethernet HW pads packets on transmit, however in our case 2070 // some packets do not travel over Ethernet but being routed 2071 // guest-to-guest by virtual switch. 2072 // In this case padding is not performed and we may 2073 // receive packet smaller than minimal allowed size. This is not 2074 // a problem for real life scenarios however WHQL/HCK contains 2075 // tests that check padding of received packets. 2076 // To make these tests happy we have to pad small packets on receive 2077 2078 //NOTE: This function assumes that VLAN header has been already stripped out 2079 2080 if(*pLength < ETH_MIN_PACKET_SIZE) 2081 { 2082 RtlZeroMemory(RtlOffsetToPointer(pDataBuffer, *pLength), ETH_MIN_PACKET_SIZE - *pLength); 2083 *pLength = ETH_MIN_PACKET_SIZE; 2084 } 2085 } 2086 2087 /********************************************************** 2088 Manages RX path, calling NDIS-specific procedure for packet indication 2089 Parameters: 2090 context 2091 ***********************************************************/ 2092 static UINT ParaNdis_ProcessRxPath(PARANDIS_ADAPTER *pContext, ULONG ulMaxPacketsToIndicate) 2093 { 2094 pIONetDescriptor pBuffersDescriptor; 2095 UINT len, headerSize = pContext->nVirtioHeaderSize; 2096 eInspectedPacketType packetType = iptInvalid; 2097 UINT nReceived = 0, nRetrieved = 0, nReported = 0; 2098 tPacketIndicationType *pBatchOfPackets; 2099 UINT maxPacketsInBatch = pContext->NetMaxReceiveBuffers; 2100 pBatchOfPackets = pContext->bBatchReceive ? 2101 ParaNdis_AllocateMemory(pContext, maxPacketsInBatch * sizeof(tPacketIndicationType)) : NULL; 2102 NdisAcquireSpinLock(&pContext->ReceiveLock); 2103 while ((nReported < ulMaxPacketsToIndicate) && NULL != (pBuffersDescriptor = virtqueue_get_buf(pContext->NetReceiveQueue, &len))) 2104 { 2105 PVOID pDataBuffer = RtlOffsetToPointer(pBuffersDescriptor->DataInfo.Virtual, pContext->bUseMergedBuffers ? pContext->nVirtioHeaderSize : 0); 2106 RemoveEntryList(&pBuffersDescriptor->listEntry); 2107 InsertTailList(&pContext->NetReceiveBuffersWaiting, &pBuffersDescriptor->listEntry); 2108 pContext->NetNofReceiveBuffers--; 2109 nRetrieved++; 2110 DPrintf(2, ("[%s] retrieved header+%d b.", __FUNCTION__, len - headerSize)); 2111 DebugDumpPacket("receive", pDataBuffer, 3); 2112 2113 if( !pContext->bSurprizeRemoved && 2114 ShallPassPacket(pContext, pDataBuffer, len - headerSize, &packetType) && 2115 pContext->ReceiveState == srsEnabled && 2116 pContext->bConnected) 2117 { 2118 BOOLEAN b = FALSE; 2119 ULONG length = len - headerSize; 2120 if (!pBatchOfPackets) 2121 { 2122 NdisReleaseSpinLock(&pContext->ReceiveLock); 2123 b = NULL != ParaNdis_IndicateReceivedPacket( 2124 pContext, 2125 pDataBuffer, 2126 &length, 2127 FALSE, 2128 pBuffersDescriptor); 2129 NdisAcquireSpinLock(&pContext->ReceiveLock); 2130 } 2131 else 2132 { 2133 tPacketIndicationType packet; 2134 packet = ParaNdis_IndicateReceivedPacket( 2135 pContext, 2136 pDataBuffer, 2137 &length, 2138 TRUE, 2139 pBuffersDescriptor); 2140 b = packet != NULL; 2141 if (b) pBatchOfPackets[nReceived] = packet; 2142 } 2143 if (!b) 2144 { 2145 pContext->ReuseBufferProc(pContext, pBuffersDescriptor); 2146 //only possible reason for that is unexpected Vlan tag 2147 //shall I count it as error? 2148 pContext->Statistics.ifInErrors++; 2149 pContext->Statistics.ifInDiscards++; 2150 } 2151 else 2152 { 2153 nReceived++; 2154 nReported++; 2155 pContext->Statistics.ifHCInOctets += length; 2156 switch(packetType) 2157 { 2158 case iptBroadcast: 2159 pContext->Statistics.ifHCInBroadcastPkts++; 2160 pContext->Statistics.ifHCInBroadcastOctets += length; 2161 break; 2162 case iptMulticast: 2163 pContext->Statistics.ifHCInMulticastPkts++; 2164 pContext->Statistics.ifHCInMulticastOctets += length; 2165 break; 2166 default: 2167 pContext->Statistics.ifHCInUcastPkts++; 2168 pContext->Statistics.ifHCInUcastOctets += length; 2169 break; 2170 } 2171 if (pBatchOfPackets && nReceived == maxPacketsInBatch) 2172 { 2173 DPrintf(1, ("[%s] received %d buffers of max %d", __FUNCTION__, nReceived, ulMaxPacketsToIndicate)); 2174 NdisReleaseSpinLock(&pContext->ReceiveLock); 2175 ParaNdis_IndicateReceivedBatch(pContext, pBatchOfPackets, nReceived); 2176 NdisAcquireSpinLock(&pContext->ReceiveLock); 2177 nReceived = 0; 2178 } 2179 } 2180 } 2181 else 2182 { 2183 // reuse packet, there is no data or the RX is suppressed 2184 pContext->ReuseBufferProc(pContext, pBuffersDescriptor); 2185 } 2186 } 2187 ParaNdis_DebugHistory(pContext, hopReceiveStat, NULL, nRetrieved, nReported, pContext->NetNofReceiveBuffers); 2188 NdisReleaseSpinLock(&pContext->ReceiveLock); 2189 if (nReceived && pBatchOfPackets) 2190 { 2191 DPrintf(1, ("[%s]%d: received %d buffers of max %d", __FUNCTION__, KeGetCurrentProcessorNumber(), nReceived, ulMaxPacketsToIndicate)); 2192 ParaNdis_IndicateReceivedBatch(pContext, pBatchOfPackets, nReceived); 2193 } 2194 if (pBatchOfPackets) NdisFreeMemory(pBatchOfPackets, 0, 0); 2195 return nReported; 2196 } 2197 2198 void ParaNdis_ReportLinkStatus(PARANDIS_ADAPTER *pContext, BOOLEAN bForce) 2199 { 2200 BOOLEAN bConnected = TRUE; 2201 if (pContext->bLinkDetectSupported) 2202 { 2203 USHORT linkStatus = 0; 2204 USHORT offset = sizeof(pContext->CurrentMacAddress); 2205 // link changed 2206 virtio_get_config(&pContext->IODevice, offset, &linkStatus, sizeof(linkStatus)); 2207 bConnected = (linkStatus & VIRTIO_NET_S_LINK_UP) != 0; 2208 } 2209 ParaNdis_IndicateConnect(pContext, bConnected, bForce); 2210 } 2211 2212 static BOOLEAN NTAPI RestartQueueSynchronously(tSynchronizedContext *SyncContext) 2213 { 2214 struct virtqueue * _vq = (struct virtqueue *) SyncContext->Parameter; 2215 bool res = true; 2216 if (!virtqueue_enable_cb(_vq)) 2217 { 2218 virtqueue_disable_cb(_vq); 2219 res = false; 2220 } 2221 2222 ParaNdis_DebugHistory(SyncContext->pContext, hopDPC, (PVOID)SyncContext->Parameter, 0x20, res, 0); 2223 return !res; 2224 } 2225 /********************************************************** 2226 DPC implementation, common for both NDIS 2227 Parameters: 2228 context 2229 ***********************************************************/ 2230 ULONG ParaNdis_DPCWorkBody(PARANDIS_ADAPTER *pContext, ULONG ulMaxPacketsToIndicate) 2231 { 2232 ULONG stillRequiresProcessing = 0; 2233 ULONG interruptSources; 2234 UINT uIndicatedRXPackets = 0; 2235 UINT numOfPacketsToIndicate = min(ulMaxPacketsToIndicate, pContext->uNumberOfHandledRXPacketsInDPC); 2236 2237 DEBUG_ENTRY(5); 2238 if (pContext->bEnableInterruptHandlingDPC) 2239 { 2240 InterlockedIncrement(&pContext->counterDPCInside); 2241 if (pContext->bEnableInterruptHandlingDPC) 2242 { 2243 BOOLEAN bDoKick = FALSE; 2244 2245 InterlockedExchange(&pContext->bDPCInactive, 0); 2246 interruptSources = InterlockedExchange(&pContext->InterruptStatus, 0); 2247 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)1, interruptSources, 0, 0); 2248 if ((interruptSources & isControl) && pContext->bLinkDetectSupported) 2249 { 2250 ParaNdis_ReportLinkStatus(pContext, FALSE); 2251 } 2252 if (interruptSources & isTransmit) 2253 { 2254 bDoKick = ParaNdis_ProcessTx(pContext, TRUE, TRUE); 2255 } 2256 if (interruptSources & isReceive) 2257 { 2258 int nRestartResult = 0; 2259 2260 do 2261 { 2262 LONG rxActive = InterlockedIncrement(&pContext->dpcReceiveActive); 2263 if (rxActive == 1) 2264 { 2265 uIndicatedRXPackets += ParaNdis_ProcessRxPath(pContext, numOfPacketsToIndicate - uIndicatedRXPackets); 2266 InterlockedDecrement(&pContext->dpcReceiveActive); 2267 NdisAcquireSpinLock(&pContext->ReceiveLock); 2268 nRestartResult = ParaNdis_SynchronizeWithInterrupt( 2269 pContext, pContext->ulRxMessage, RestartQueueSynchronously, pContext->NetReceiveQueue); 2270 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)3, nRestartResult, 0, 0); 2271 NdisReleaseSpinLock(&pContext->ReceiveLock); 2272 DPrintf(nRestartResult ? 2 : 6, ("[%s] queue restarted%s", __FUNCTION__, nRestartResult ? "(Rerun)" : "(Done)")); 2273 2274 if (uIndicatedRXPackets < numOfPacketsToIndicate) 2275 { 2276 2277 } 2278 else if (uIndicatedRXPackets == numOfPacketsToIndicate) 2279 { 2280 DPrintf(1, ("[%s] Breaking Rx loop after %d indications", __FUNCTION__, uIndicatedRXPackets)); 2281 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)4, nRestartResult, 0, 0); 2282 break; 2283 } 2284 else 2285 { 2286 DPrintf(0, ("[%s] Glitch found: %d allowed, %d indicated", __FUNCTION__, numOfPacketsToIndicate, uIndicatedRXPackets)); 2287 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)6, nRestartResult, 0, 0); 2288 } 2289 } 2290 else 2291 { 2292 InterlockedDecrement(&pContext->dpcReceiveActive); 2293 if (!nRestartResult) 2294 { 2295 NdisAcquireSpinLock(&pContext->ReceiveLock); 2296 nRestartResult = ParaNdis_SynchronizeWithInterrupt( 2297 pContext, pContext->ulRxMessage, RestartQueueSynchronously, pContext->NetReceiveQueue); 2298 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)5, nRestartResult, 0, 0); 2299 NdisReleaseSpinLock(&pContext->ReceiveLock); 2300 } 2301 DPrintf(1, ("[%s] Skip Rx processing no.%d", __FUNCTION__, rxActive)); 2302 break; 2303 } 2304 } while (nRestartResult); 2305 2306 if (nRestartResult) stillRequiresProcessing |= isReceive; 2307 } 2308 2309 if (interruptSources & isTransmit) 2310 { 2311 NdisAcquireSpinLock(&pContext->SendLock); 2312 if (ParaNdis_SynchronizeWithInterrupt(pContext, pContext->ulTxMessage, RestartQueueSynchronously, pContext->NetSendQueue)) 2313 stillRequiresProcessing |= isTransmit; 2314 if(bDoKick) 2315 { 2316 #ifdef PARANDIS_TEST_TX_KICK_ALWAYS 2317 virtqueue_kick_always(pContext->NetSendQueue); 2318 #else 2319 virtqueue_kick(pContext->NetSendQueue); 2320 #endif 2321 } 2322 NdisReleaseSpinLock(&pContext->SendLock); 2323 } 2324 } 2325 InterlockedDecrement(&pContext->counterDPCInside); 2326 ParaNdis_DebugHistory(pContext, hopDPC, NULL, stillRequiresProcessing, pContext->nofFreeHardwareBuffers, pContext->nofFreeTxDescriptors); 2327 } 2328 return stillRequiresProcessing; 2329 } 2330 2331 /********************************************************** 2332 Periodically called procedure, checking dpc activity 2333 If DPC are not running, it does exactly the same that the DPC 2334 Parameters: 2335 context 2336 ***********************************************************/ 2337 static BOOLEAN CheckRunningDpc(PARANDIS_ADAPTER *pContext) 2338 { 2339 BOOLEAN bStopped; 2340 BOOLEAN bReportHang = FALSE; 2341 bStopped = 0 != InterlockedExchange(&pContext->bDPCInactive, TRUE); 2342 2343 if (bStopped) 2344 { 2345 pContext->nDetectedInactivity++; 2346 if (pContext->nEnableDPCChecker) 2347 { 2348 if (pContext->NetTxPacketsToReturn) 2349 { 2350 DPrintf(0, ("[%s] - NO ACTIVITY!", __FUNCTION__)); 2351 if (!pContext->Limits.nPrintDiagnostic) PrintStatistics(pContext); 2352 if (pContext->nEnableDPCChecker > 1) 2353 { 2354 int isrStatus1, isrStatus2; 2355 isrStatus1 = virtio_read_isr_status(&pContext->IODevice); 2356 isrStatus2 = virtio_read_isr_status(&pContext->IODevice); 2357 if (isrStatus1 || isrStatus2) 2358 { 2359 DPrintf(0, ("WARNING: Interrupt status %d=>%d", isrStatus1, isrStatus2)); 2360 } 2361 } 2362 // simulateDPC 2363 InterlockedOr(&pContext->InterruptStatus, isAny); 2364 ParaNdis_DPCWorkBody(pContext, PARANDIS_UNLIMITED_PACKETS_TO_INDICATE); 2365 } 2366 } 2367 } 2368 else 2369 { 2370 pContext->nDetectedInactivity = 0; 2371 } 2372 2373 NdisAcquireSpinLock(&pContext->SendLock); 2374 if (pContext->nofFreeHardwareBuffers != pContext->maxFreeHardwareBuffers) 2375 { 2376 if (pContext->nDetectedStoppedTx++ > 1) 2377 { 2378 DPrintf(0, ("[%s] - Suspicious Tx inactivity (%d)!", __FUNCTION__, pContext->nofFreeHardwareBuffers)); 2379 //bReportHang = TRUE; 2380 #ifdef DBG_USE_VIRTIO_PCI_ISR_FOR_HOST_REPORT 2381 WriteVirtIODeviceByte(pContext->IODevice.isr, 0); 2382 #endif 2383 } 2384 } 2385 NdisReleaseSpinLock(&pContext->SendLock); 2386 2387 2388 if (pContext->Limits.nPrintDiagnostic && 2389 ++pContext->Counters.nPrintDiagnostic >= pContext->Limits.nPrintDiagnostic) 2390 { 2391 pContext->Counters.nPrintDiagnostic = 0; 2392 // todo - collect more and put out optionally 2393 PrintStatistics(pContext); 2394 } 2395 2396 if (pContext->Statistics.ifHCInOctets == pContext->Counters.prevIn) 2397 { 2398 pContext->Counters.nRxInactivity++; 2399 if (pContext->Counters.nRxInactivity >= 10) 2400 { 2401 //#define CRASH_ON_NO_RX 2402 #if defined(CRASH_ON_NO_RX) 2403 ONPAUSECOMPLETEPROC proc = (ONPAUSECOMPLETEPROC)(PVOID)1; 2404 proc(pContext); 2405 #endif 2406 } 2407 } 2408 else 2409 { 2410 pContext->Counters.nRxInactivity = 0; 2411 pContext->Counters.prevIn = pContext->Statistics.ifHCInOctets; 2412 } 2413 return bReportHang; 2414 } 2415 2416 /********************************************************** 2417 Common implementation of periodic poll 2418 Parameters: 2419 context 2420 Return: 2421 TRUE, if reset required 2422 ***********************************************************/ 2423 BOOLEAN ParaNdis_CheckForHang(PARANDIS_ADAPTER *pContext) 2424 { 2425 static int nHangOn = 0; 2426 BOOLEAN b = nHangOn >= 3 && nHangOn < 6; 2427 DEBUG_ENTRY(3); 2428 b |= CheckRunningDpc(pContext); 2429 //uncomment to cause 3 consecutive resets 2430 //nHangOn++; 2431 DEBUG_EXIT_STATUS(b ? 0 : 6, b); 2432 return b; 2433 } 2434 2435 /********************************************************** 2436 Common handler of multicast address configuration 2437 Parameters: 2438 PVOID Buffer array of addresses from NDIS 2439 ULONG BufferSize size of incoming buffer 2440 PUINT pBytesRead update on success 2441 PUINT pBytesNeeded update on wrong buffer size 2442 Return value: 2443 SUCCESS or kind of failure 2444 ***********************************************************/ 2445 NDIS_STATUS ParaNdis_SetMulticastList( 2446 PARANDIS_ADAPTER *pContext, 2447 PVOID Buffer, 2448 ULONG BufferSize, 2449 PUINT pBytesRead, 2450 PUINT pBytesNeeded) 2451 { 2452 NDIS_STATUS status; 2453 ULONG length = BufferSize; 2454 if (length > sizeof(pContext->MulticastData.MulticastList)) 2455 { 2456 status = NDIS_STATUS_MULTICAST_FULL; 2457 *pBytesNeeded = sizeof(pContext->MulticastData.MulticastList); 2458 } 2459 else if (length % ETH_LENGTH_OF_ADDRESS) 2460 { 2461 status = NDIS_STATUS_INVALID_LENGTH; 2462 *pBytesNeeded = (length / ETH_LENGTH_OF_ADDRESS) * ETH_LENGTH_OF_ADDRESS; 2463 } 2464 else 2465 { 2466 NdisZeroMemory(pContext->MulticastData.MulticastList, sizeof(pContext->MulticastData.MulticastList)); 2467 if (length) 2468 NdisMoveMemory(pContext->MulticastData.MulticastList, Buffer, length); 2469 pContext->MulticastData.nofMulticastEntries = length / ETH_LENGTH_OF_ADDRESS; 2470 DPrintf(1, ("[%s] New multicast list of %d bytes", __FUNCTION__, length)); 2471 *pBytesRead = length; 2472 status = NDIS_STATUS_SUCCESS; 2473 } 2474 return status; 2475 } 2476 2477 /********************************************************** 2478 Callable from synchronized routine or interrupt handler 2479 to enable or disable Rx and/or Tx interrupt generation 2480 Parameters: 2481 context 2482 interruptSource - isReceive, isTransmit 2483 b - 1/0 enable/disable 2484 ***********************************************************/ 2485 VOID ParaNdis_VirtIOEnableIrqSynchronized(PARANDIS_ADAPTER *pContext, ULONG interruptSource) 2486 { 2487 if (interruptSource & isTransmit) 2488 virtqueue_enable_cb(pContext->NetSendQueue); 2489 if (interruptSource & isReceive) 2490 virtqueue_enable_cb(pContext->NetReceiveQueue); 2491 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)0x10, interruptSource, TRUE, 0); 2492 } 2493 2494 VOID ParaNdis_VirtIODisableIrqSynchronized(PARANDIS_ADAPTER *pContext, ULONG interruptSource) 2495 { 2496 if (interruptSource & isTransmit) 2497 virtqueue_disable_cb(pContext->NetSendQueue); 2498 if (interruptSource & isReceive) 2499 virtqueue_disable_cb(pContext->NetReceiveQueue); 2500 ParaNdis_DebugHistory(pContext, hopDPC, (PVOID)0x10, interruptSource, FALSE, 0); 2501 } 2502 2503 /********************************************************** 2504 Common handler of PnP events 2505 Parameters: 2506 Return value: 2507 ***********************************************************/ 2508 VOID ParaNdis_OnPnPEvent( 2509 PARANDIS_ADAPTER *pContext, 2510 NDIS_DEVICE_PNP_EVENT pEvent, 2511 PVOID pInfo, 2512 ULONG ulSize) 2513 { 2514 const char *pName = ""; 2515 DEBUG_ENTRY(0); 2516 #undef MAKECASE 2517 #define MAKECASE(x) case (x): pName = #x; break; 2518 switch (pEvent) 2519 { 2520 MAKECASE(NdisDevicePnPEventQueryRemoved) 2521 MAKECASE(NdisDevicePnPEventRemoved) 2522 MAKECASE(NdisDevicePnPEventSurpriseRemoved) 2523 MAKECASE(NdisDevicePnPEventQueryStopped) 2524 MAKECASE(NdisDevicePnPEventStopped) 2525 MAKECASE(NdisDevicePnPEventPowerProfileChanged) 2526 default: 2527 break; 2528 } 2529 ParaNdis_DebugHistory(pContext, hopPnpEvent, NULL, pEvent, 0, 0); 2530 DPrintf(0, ("[%s] (%s)", __FUNCTION__, pName)); 2531 if (pEvent == NdisDevicePnPEventSurpriseRemoved) 2532 { 2533 // on simulated surprise removal (under PnpTest) we need to reset the device 2534 // to prevent any access of device queues to memory buffers 2535 pContext->bSurprizeRemoved = TRUE; 2536 ParaNdis_ResetVirtIONetDevice(pContext); 2537 } 2538 pContext->PnpEvents[pContext->nPnpEventIndex++] = pEvent; 2539 if (pContext->nPnpEventIndex > sizeof(pContext->PnpEvents)/sizeof(pContext->PnpEvents[0])) 2540 pContext->nPnpEventIndex = 0; 2541 } 2542 2543 static BOOLEAN SendControlMessage( 2544 PARANDIS_ADAPTER *pContext, 2545 UCHAR cls, 2546 UCHAR cmd, 2547 PVOID buffer1, 2548 ULONG size1, 2549 PVOID buffer2, 2550 ULONG size2, 2551 int levelIfOK 2552 ) 2553 { 2554 BOOLEAN bOK = FALSE; 2555 NdisAcquireSpinLock(&pContext->ReceiveLock); 2556 if (pContext->ControlData.Virtual && pContext->ControlData.size > (size1 + size2 + 16)) 2557 { 2558 struct VirtIOBufferDescriptor sg[4]; 2559 PUCHAR pBase = (PUCHAR)pContext->ControlData.Virtual; 2560 PHYSICAL_ADDRESS phBase = pContext->ControlData.Physical; 2561 ULONG offset = 0; 2562 UINT nOut = 1; 2563 2564 ((virtio_net_ctrl_hdr *)pBase)->class_of_command = cls; 2565 ((virtio_net_ctrl_hdr *)pBase)->cmd = cmd; 2566 sg[0].physAddr = phBase; 2567 sg[0].length = sizeof(virtio_net_ctrl_hdr); 2568 offset += sg[0].length; 2569 offset = (offset + 3) & ~3; 2570 if (size1) 2571 { 2572 NdisMoveMemory(pBase + offset, buffer1, size1); 2573 sg[nOut].physAddr = phBase; 2574 sg[nOut].physAddr.QuadPart += offset; 2575 sg[nOut].length = size1; 2576 offset += size1; 2577 offset = (offset + 3) & ~3; 2578 nOut++; 2579 } 2580 if (size2) 2581 { 2582 NdisMoveMemory(pBase + offset, buffer2, size2); 2583 sg[nOut].physAddr = phBase; 2584 sg[nOut].physAddr.QuadPart += offset; 2585 sg[nOut].length = size2; 2586 offset += size2; 2587 offset = (offset + 3) & ~3; 2588 nOut++; 2589 } 2590 sg[nOut].physAddr = phBase; 2591 sg[nOut].physAddr.QuadPart += offset; 2592 sg[nOut].length = sizeof(virtio_net_ctrl_ack); 2593 *(virtio_net_ctrl_ack *)(pBase + offset) = VIRTIO_NET_ERR; 2594 2595 if (0 <= virtqueue_add_buf(pContext->NetControlQueue, sg, nOut, 1, (PVOID)1, NULL, 0)) 2596 { 2597 UINT len; 2598 void *p; 2599 virtqueue_kick_always(pContext->NetControlQueue); 2600 p = virtqueue_get_buf(pContext->NetControlQueue, &len); 2601 if (!p) 2602 { 2603 DPrintf(0, ("%s - ERROR: get_buf failed", __FUNCTION__)); 2604 } 2605 else if (len != sizeof(virtio_net_ctrl_ack)) 2606 { 2607 DPrintf(0, ("%s - ERROR: wrong len %d", __FUNCTION__, len)); 2608 } 2609 else if (*(virtio_net_ctrl_ack *)(pBase + offset) != VIRTIO_NET_OK) 2610 { 2611 DPrintf(0, ("%s - ERROR: error %d returned", __FUNCTION__, *(virtio_net_ctrl_ack *)(pBase + offset))); 2612 } 2613 else 2614 { 2615 // everything is OK 2616 DPrintf(levelIfOK, ("%s OK(%d.%d,buffers of %d and %d) ", __FUNCTION__, cls, cmd, size1, size2)); 2617 bOK = TRUE; 2618 } 2619 } 2620 else 2621 { 2622 DPrintf(0, ("%s - ERROR: add_buf failed", __FUNCTION__)); 2623 } 2624 } 2625 else 2626 { 2627 DPrintf(0, ("%s (buffer %d,%d) - ERROR: message too LARGE", __FUNCTION__, size1, size2)); 2628 } 2629 NdisReleaseSpinLock(&pContext->ReceiveLock); 2630 return bOK; 2631 } 2632 2633 static VOID ParaNdis_DeviceFiltersUpdateRxMode(PARANDIS_ADAPTER *pContext) 2634 { 2635 u8 val; 2636 ULONG f = pContext->PacketFilter; 2637 val = (f & NDIS_PACKET_TYPE_ALL_MULTICAST) ? 1 : 0; 2638 SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_ALLMULTI, &val, sizeof(val), NULL, 0, 2); 2639 //SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_ALLUNI, &val, sizeof(val), NULL, 0, 2); 2640 val = (f & (NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_ALL_MULTICAST)) ? 0 : 1; 2641 SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_NOMULTI, &val, sizeof(val), NULL, 0, 2); 2642 val = (f & NDIS_PACKET_TYPE_DIRECTED) ? 0 : 1; 2643 SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_NOUNI, &val, sizeof(val), NULL, 0, 2); 2644 val = (f & NDIS_PACKET_TYPE_BROADCAST) ? 0 : 1; 2645 SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_NOBCAST, &val, sizeof(val), NULL, 0, 2); 2646 val = (f & NDIS_PACKET_TYPE_PROMISCUOUS) ? 1 : 0; 2647 SendControlMessage(pContext, VIRTIO_NET_CTRL_RX_MODE, VIRTIO_NET_CTRL_RX_MODE_PROMISC, &val, sizeof(val), NULL, 0, 2); 2648 } 2649 2650 static VOID ParaNdis_DeviceFiltersUpdateAddresses(PARANDIS_ADAPTER *pContext) 2651 { 2652 struct 2653 { 2654 struct virtio_net_ctrl_mac header; 2655 UCHAR addr[ETH_LENGTH_OF_ADDRESS]; 2656 } uCast; 2657 uCast.header.entries = 1; 2658 NdisMoveMemory(uCast.addr, pContext->CurrentMacAddress, sizeof(uCast.addr)); 2659 SendControlMessage(pContext, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_TABLE_SET, 2660 &uCast, sizeof(uCast), &pContext->MulticastData,sizeof(pContext->MulticastData.nofMulticastEntries) + pContext->MulticastData.nofMulticastEntries * ETH_ALEN, 2); 2661 } 2662 2663 static VOID SetSingleVlanFilter(PARANDIS_ADAPTER *pContext, ULONG vlanId, BOOLEAN bOn, int levelIfOK) 2664 { 2665 u16 val = vlanId & 0xfff; 2666 UCHAR cmd = bOn ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL; 2667 SendControlMessage(pContext, VIRTIO_NET_CTRL_VLAN, cmd, &val, sizeof(val), NULL, 0, levelIfOK); 2668 } 2669 2670 static VOID SetAllVlanFilters(PARANDIS_ADAPTER *pContext, BOOLEAN bOn) 2671 { 2672 ULONG i; 2673 for (i = 0; i <= MAX_VLAN_ID; ++i) 2674 SetSingleVlanFilter(pContext, i, bOn, 7); 2675 } 2676 2677 /* 2678 possible values of filter set (pContext->ulCurrentVlansFilterSet): 2679 0 - all disabled 2680 1..4095 - one selected enabled 2681 4096 - all enabled 2682 Note that only 0th vlan can't be enabled 2683 */ 2684 VOID ParaNdis_DeviceFiltersUpdateVlanId(PARANDIS_ADAPTER *pContext) 2685 { 2686 if (pContext->bHasHardwareFilters) 2687 { 2688 ULONG newFilterSet; 2689 if (IsVlanSupported(pContext)) 2690 newFilterSet = pContext->VlanId ? pContext->VlanId : (MAX_VLAN_ID + 1); 2691 else 2692 newFilterSet = IsPrioritySupported(pContext) ? (MAX_VLAN_ID + 1) : 0; 2693 if (newFilterSet != pContext->ulCurrentVlansFilterSet) 2694 { 2695 if (pContext->ulCurrentVlansFilterSet > MAX_VLAN_ID) 2696 SetAllVlanFilters(pContext, FALSE); 2697 else if (pContext->ulCurrentVlansFilterSet) 2698 SetSingleVlanFilter(pContext, pContext->ulCurrentVlansFilterSet, FALSE, 2); 2699 2700 pContext->ulCurrentVlansFilterSet = newFilterSet; 2701 2702 if (pContext->ulCurrentVlansFilterSet > MAX_VLAN_ID) 2703 SetAllVlanFilters(pContext, TRUE); 2704 else if (pContext->ulCurrentVlansFilterSet) 2705 SetSingleVlanFilter(pContext, pContext->ulCurrentVlansFilterSet, TRUE, 2); 2706 } 2707 } 2708 } 2709 2710 VOID ParaNdis_UpdateDeviceFilters(PARANDIS_ADAPTER *pContext) 2711 { 2712 if (pContext->bHasHardwareFilters) 2713 { 2714 ParaNdis_DeviceFiltersUpdateRxMode(pContext); 2715 ParaNdis_DeviceFiltersUpdateAddresses(pContext); 2716 ParaNdis_DeviceFiltersUpdateVlanId(pContext); 2717 } 2718 } 2719 2720 NDIS_STATUS ParaNdis_PowerOn(PARANDIS_ADAPTER *pContext) 2721 { 2722 LIST_ENTRY TempList; 2723 NDIS_STATUS status; 2724 DEBUG_ENTRY(0); 2725 ParaNdis_DebugHistory(pContext, hopPowerOn, NULL, 1, 0, 0); 2726 ParaNdis_ResetVirtIONetDevice(pContext); 2727 virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER); 2728 /* virtio_get_features must be called once upon device initialization: 2729 otherwise the device will not work properly */ 2730 (void)virtio_get_features(&pContext->IODevice); 2731 2732 if (pContext->bUseMergedBuffers) 2733 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_MRG_RXBUF); 2734 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_RING_F_EVENT_IDX)) 2735 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_RING_F_EVENT_IDX); 2736 if (pContext->bDoGuestChecksumOnReceive) 2737 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_NET_F_GUEST_CSUM); 2738 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_VERSION_1)) 2739 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_VERSION_1); 2740 if (VirtIODeviceGetHostFeature(pContext, VIRTIO_F_ANY_LAYOUT)) 2741 VirtIODeviceEnableGuestFeature(pContext, VIRTIO_F_ANY_LAYOUT); 2742 2743 status = FinalizeFeatures(pContext); 2744 if (status == NDIS_STATUS_SUCCESS) { 2745 status = FindNetQueues(pContext); 2746 } 2747 if (status != NDIS_STATUS_SUCCESS) { 2748 virtio_add_status(&pContext->IODevice, VIRTIO_CONFIG_S_FAILED); 2749 return status; 2750 } 2751 2752 ParaNdis_RestoreDeviceConfigurationAfterReset(pContext); 2753 2754 ParaNdis_UpdateDeviceFilters(pContext); 2755 2756 InitializeListHead(&TempList); 2757 2758 /* submit all the receive buffers */ 2759 NdisAcquireSpinLock(&pContext->ReceiveLock); 2760 2761 pContext->ReuseBufferProc = (tReuseReceiveBufferProc)ReuseReceiveBufferRegular; 2762 2763 while (!IsListEmpty(&pContext->NetReceiveBuffers)) 2764 { 2765 pIONetDescriptor pBufferDescriptor = 2766 (pIONetDescriptor)RemoveHeadList(&pContext->NetReceiveBuffers); 2767 InsertTailList(&TempList, &pBufferDescriptor->listEntry); 2768 } 2769 pContext->NetNofReceiveBuffers = 0; 2770 while (!IsListEmpty(&TempList)) 2771 { 2772 pIONetDescriptor pBufferDescriptor = 2773 (pIONetDescriptor)RemoveHeadList(&TempList); 2774 if (AddRxBufferToQueue(pContext, pBufferDescriptor)) 2775 { 2776 InsertTailList(&pContext->NetReceiveBuffers, &pBufferDescriptor->listEntry); 2777 pContext->NetNofReceiveBuffers++; 2778 } 2779 else 2780 { 2781 DPrintf(0, ("FAILED TO REUSE THE BUFFER!!!!")); 2782 VirtIONetFreeBufferDescriptor(pContext, pBufferDescriptor); 2783 pContext->NetMaxReceiveBuffers--; 2784 } 2785 } 2786 virtqueue_kick(pContext->NetReceiveQueue); 2787 ParaNdis_SetPowerState(pContext, NdisDeviceStateD0); 2788 pContext->bEnableInterruptHandlingDPC = TRUE; 2789 virtio_device_ready(&pContext->IODevice); 2790 2791 NdisReleaseSpinLock(&pContext->ReceiveLock); 2792 2793 // if bFastSuspendInProcess is set by Win8 power-off procedure, 2794 // the ParaNdis_Resume enables Tx and RX 2795 // otherwise it does not do anything in Vista+ (Tx and RX are enabled after power-on by Restart) 2796 ParaNdis_Resume(pContext); 2797 pContext->bFastSuspendInProcess = FALSE; 2798 2799 ParaNdis_ReportLinkStatus(pContext, TRUE); 2800 ParaNdis_DebugHistory(pContext, hopPowerOn, NULL, 0, 0, 0); 2801 2802 return status; 2803 } 2804 2805 VOID ParaNdis_PowerOff(PARANDIS_ADAPTER *pContext) 2806 { 2807 DEBUG_ENTRY(0); 2808 ParaNdis_DebugHistory(pContext, hopPowerOff, NULL, 1, 0, 0); 2809 2810 ParaNdis_IndicateConnect(pContext, FALSE, FALSE); 2811 2812 // if bFastSuspendInProcess is set by Win8 power-off procedure 2813 // the ParaNdis_Suspend does fast Rx stop without waiting (=>srsPausing, if there are some RX packets in Ndis) 2814 pContext->bFastSuspendInProcess = pContext->bNoPauseOnSuspend && pContext->ReceiveState == srsEnabled; 2815 ParaNdis_Suspend(pContext); 2816 if (pContext->IODevice.addr) 2817 { 2818 /* back compat - remove the OK flag only in legacy mode */ 2819 VirtIODeviceRemoveStatus(&pContext->IODevice, VIRTIO_CONFIG_S_DRIVER_OK); 2820 } 2821 2822 if (pContext->bFastSuspendInProcess) 2823 { 2824 NdisAcquireSpinLock(&pContext->ReceiveLock); 2825 pContext->ReuseBufferProc = (tReuseReceiveBufferProc)ReuseReceiveBufferPowerOff; 2826 NdisReleaseSpinLock(&pContext->ReceiveLock); 2827 } 2828 2829 ParaNdis_SetPowerState(pContext, NdisDeviceStateD3); 2830 2831 PreventDPCServicing(pContext); 2832 2833 /******************************************************************* 2834 shutdown queues to have all the receive buffers under our control 2835 all the transmit buffers move to list of free buffers 2836 ********************************************************************/ 2837 2838 NdisAcquireSpinLock(&pContext->SendLock); 2839 virtqueue_shutdown(pContext->NetSendQueue); 2840 while (!IsListEmpty(&pContext->NetSendBuffersInUse)) 2841 { 2842 pIONetDescriptor pBufferDescriptor = 2843 (pIONetDescriptor)RemoveHeadList(&pContext->NetSendBuffersInUse); 2844 InsertTailList(&pContext->NetFreeSendBuffers, &pBufferDescriptor->listEntry); 2845 pContext->nofFreeTxDescriptors++; 2846 pContext->nofFreeHardwareBuffers += pBufferDescriptor->nofUsedBuffers; 2847 } 2848 NdisReleaseSpinLock(&pContext->SendLock); 2849 2850 NdisAcquireSpinLock(&pContext->ReceiveLock); 2851 virtqueue_shutdown(pContext->NetReceiveQueue); 2852 NdisReleaseSpinLock(&pContext->ReceiveLock); 2853 if (pContext->NetControlQueue) { 2854 virtqueue_shutdown(pContext->NetControlQueue); 2855 } 2856 2857 DPrintf(0, ("WARNING: deleting queues!!!!!!!!!")); 2858 DeleteNetQueues(pContext); 2859 pContext->NetSendQueue = NULL; 2860 pContext->NetReceiveQueue = NULL; 2861 pContext->NetControlQueue = NULL; 2862 2863 ParaNdis_ResetVirtIONetDevice(pContext); 2864 ParaNdis_DebugHistory(pContext, hopPowerOff, NULL, 0, 0, 0); 2865 } 2866 2867 void ParaNdis_CallOnBugCheck(PARANDIS_ADAPTER *pContext) 2868 { 2869 if (pContext->IODevice.isr) 2870 { 2871 #ifdef DBG_USE_VIRTIO_PCI_ISR_FOR_HOST_REPORT 2872 WriteVirtIODeviceByte(pContext->IODevice.isr, 1); 2873 #endif 2874 } 2875 } 2876 2877 tChecksumCheckResult ParaNdis_CheckRxChecksum(PARANDIS_ADAPTER *pContext, ULONG virtioFlags, PVOID pRxPacket, ULONG len) 2878 { 2879 tOffloadSettingsFlags f = pContext->Offload.flags; 2880 tChecksumCheckResult res, resIp; 2881 PVOID pIpHeader = RtlOffsetToPointer(pRxPacket, ETH_HEADER_SIZE); 2882 tTcpIpPacketParsingResult ppr; 2883 ULONG flagsToCalculate = 0; 2884 res.value = 0; 2885 resIp.value = 0; 2886 2887 //VIRTIO_NET_HDR_F_NEEDS_CSUM - we need to calculate TCP/UDP CS 2888 //VIRTIO_NET_HDR_F_DATA_VALID - host tells us TCP/UDP CS is OK 2889 2890 if (f.fRxIPChecksum) flagsToCalculate |= pcrIpChecksum; // check only 2891 2892 if (!(virtioFlags & VIRTIO_NET_HDR_F_DATA_VALID)) 2893 { 2894 if (virtioFlags & VIRTIO_NET_HDR_F_NEEDS_CSUM) 2895 { 2896 flagsToCalculate |= pcrFixXxpChecksum | pcrTcpChecksum | pcrUdpChecksum; 2897 } 2898 else 2899 { 2900 if (f.fRxTCPChecksum) flagsToCalculate |= pcrTcpV4Checksum; 2901 if (f.fRxUDPChecksum) flagsToCalculate |= pcrUdpV4Checksum; 2902 if (f.fRxTCPv6Checksum) flagsToCalculate |= pcrTcpV6Checksum; 2903 if (f.fRxUDPv6Checksum) flagsToCalculate |= pcrUdpV6Checksum; 2904 } 2905 } 2906 2907 ppr = ParaNdis_CheckSumVerify(pIpHeader, len - ETH_HEADER_SIZE, flagsToCalculate, __FUNCTION__); 2908 2909 if (virtioFlags & VIRTIO_NET_HDR_F_DATA_VALID) 2910 { 2911 pContext->extraStatistics.framesRxCSHwOK++; 2912 ppr.xxpCheckSum = ppresCSOK; 2913 } 2914 2915 if (ppr.ipStatus == ppresIPV4 && !ppr.IsFragment) 2916 { 2917 if (f.fRxIPChecksum) 2918 { 2919 res.flags.IpOK = ppr.ipCheckSum == ppresCSOK; 2920 res.flags.IpFailed = ppr.ipCheckSum == ppresCSBad; 2921 } 2922 if(ppr.xxpStatus == ppresXxpKnown) 2923 { 2924 if(ppr.TcpUdp == ppresIsTCP) /* TCP */ 2925 { 2926 if (f.fRxTCPChecksum) 2927 { 2928 res.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS; 2929 res.flags.TcpFailed = !res.flags.TcpOK; 2930 } 2931 } 2932 else /* UDP */ 2933 { 2934 if (f.fRxUDPChecksum) 2935 { 2936 res.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS; 2937 res.flags.UdpFailed = !res.flags.UdpOK; 2938 } 2939 } 2940 } 2941 } 2942 else if (ppr.ipStatus == ppresIPV6) 2943 { 2944 if(ppr.xxpStatus == ppresXxpKnown) 2945 { 2946 if(ppr.TcpUdp == ppresIsTCP) /* TCP */ 2947 { 2948 if (f.fRxTCPv6Checksum) 2949 { 2950 res.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS; 2951 res.flags.TcpFailed = !res.flags.TcpOK; 2952 } 2953 } 2954 else /* UDP */ 2955 { 2956 if (f.fRxUDPv6Checksum) 2957 { 2958 res.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK || ppr.fixedXxpCS; 2959 res.flags.UdpFailed = !res.flags.UdpOK; 2960 } 2961 } 2962 } 2963 } 2964 2965 if (pContext->bDoIPCheckRx && 2966 (f.fRxIPChecksum || f.fRxTCPChecksum || f.fRxUDPChecksum || f.fRxTCPv6Checksum || f.fRxUDPv6Checksum)) 2967 { 2968 ppr = ParaNdis_CheckSumVerify(pIpHeader, len - ETH_HEADER_SIZE, pcrAnyChecksum, __FUNCTION__); 2969 if (ppr.ipStatus == ppresIPV4 && !ppr.IsFragment) 2970 { 2971 resIp.flags.IpOK = !!f.fRxIPChecksum && ppr.ipCheckSum == ppresCSOK; 2972 resIp.flags.IpFailed = !!f.fRxIPChecksum && ppr.ipCheckSum == ppresCSBad; 2973 if (f.fRxTCPChecksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsTCP) 2974 { 2975 resIp.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK; 2976 resIp.flags.TcpFailed = ppr.xxpCheckSum == ppresCSBad; 2977 } 2978 if (f.fRxUDPChecksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsUDP) 2979 { 2980 resIp.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK; 2981 resIp.flags.UdpFailed = ppr.xxpCheckSum == ppresCSBad; 2982 } 2983 } 2984 else if (ppr.ipStatus == ppresIPV6) 2985 { 2986 if (f.fRxTCPv6Checksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsTCP) 2987 { 2988 resIp.flags.TcpOK = ppr.xxpCheckSum == ppresCSOK; 2989 resIp.flags.TcpFailed = ppr.xxpCheckSum == ppresCSBad; 2990 } 2991 if (f.fRxUDPv6Checksum && ppr.xxpStatus == ppresXxpKnown && ppr.TcpUdp == ppresIsUDP) 2992 { 2993 resIp.flags.UdpOK = ppr.xxpCheckSum == ppresCSOK; 2994 resIp.flags.UdpFailed = ppr.xxpCheckSum == ppresCSBad; 2995 } 2996 } 2997 2998 if (res.value != resIp.value) 2999 { 3000 // if HW did not set some bits that IP checker set, it is a mistake: 3001 // or GOOD CS is not labeled, or BAD checksum is not labeled 3002 tChecksumCheckResult diff; 3003 diff.value = resIp.value & ~res.value; 3004 if (diff.flags.IpFailed || diff.flags.TcpFailed || diff.flags.UdpFailed) 3005 pContext->extraStatistics.framesRxCSHwMissedBad++; 3006 if (diff.flags.IpOK || diff.flags.TcpOK || diff.flags.UdpOK) 3007 pContext->extraStatistics.framesRxCSHwMissedGood++; 3008 if (diff.value) 3009 { 3010 DPrintf(0, ("[%s] real %X <> %X (virtio %X)", __FUNCTION__, resIp.value, res.value, virtioFlags)); 3011 } 3012 res.value = resIp.value; 3013 } 3014 } 3015 3016 return res; 3017 } 3018