1 /* 2 * This file contains NDIS5.X Implementation of adapter driver procedures. 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 "ParaNdis5.h" 30 31 32 #ifdef WPP_EVENT_TRACING 33 #include "ParaNdis5-Impl.tmh" 34 #endif 35 36 37 /********************************************************** 38 Per-packet information holder 39 ***********************************************************/ 40 #define SEND_ENTRY_FLAG_READY 0x0001 41 #define SEND_ENTRY_TSO_USED 0x0002 42 #define SEND_ENTRY_NO_INDIRECT 0x0004 43 #define SEND_ENTRY_TCP_CS 0x0008 44 #define SEND_ENTRY_UDP_CS 0x0010 45 #define SEND_ENTRY_IP_CS 0x0020 46 47 48 49 typedef struct _tagSendEntry 50 { 51 LIST_ENTRY list; 52 PNDIS_PACKET packet; 53 ULONG flags; 54 ULONG ipTransferUnit; 55 union 56 { 57 ULONG PriorityDataLong; 58 UCHAR PriorityData[4]; 59 }; 60 } tSendEntry; 61 62 /********************************************************** 63 This defines field in NDIS_PACKET structure to use as holder 64 of our reference pointer for indicated packets 65 ***********************************************************/ 66 #define IDXTOUSE 0 67 #define REF_MINIPORT(Packet) ((PVOID *)(Packet->MiniportReservedEx + IDXTOUSE * sizeof(PVOID))) 68 69 70 /********************************************************** 71 Memory allocation procedure 72 Parameters: 73 context(not used) 74 ULONG ulRequiredSize size of block to allocate 75 Return value: 76 PVOID pointer to block or NULL if failed 77 ***********************************************************/ 78 PVOID ParaNdis_AllocateMemory(PARANDIS_ADAPTER *pContext, ULONG ulRequiredSize) 79 { 80 PVOID p; 81 UNREFERENCED_PARAMETER(pContext); 82 if (NDIS_STATUS_SUCCESS != NdisAllocateMemoryWithTag(&p, ulRequiredSize, PARANDIS_MEMORY_TAG)) 83 p = NULL; 84 if (!p) 85 { 86 DPrintf(0, ("[%s] failed (%d bytes)", __FUNCTION__, ulRequiredSize)); 87 } 88 return p; 89 } 90 91 /********************************************************** 92 Implementation of "open adapter configuration" operation 93 Parameters: 94 context 95 Return value: 96 NDIS_HANDLE Handle to open configuration or NULL, if failed 97 ***********************************************************/ 98 NDIS_HANDLE ParaNdis_OpenNICConfiguration(PARANDIS_ADAPTER *pContext) 99 { 100 NDIS_STATUS status; 101 NDIS_HANDLE cfg; 102 DEBUG_ENTRY(2); 103 NdisOpenConfiguration(&status, &cfg, pContext->WrapperConfigurationHandle); 104 if (status != NDIS_STATUS_SUCCESS) 105 cfg = NULL; 106 DEBUG_EXIT_STATUS(0, status); 107 return cfg; 108 } 109 110 void ParaNdis_RestoreDeviceConfigurationAfterReset( 111 PARANDIS_ADAPTER *pContext) 112 { 113 114 } 115 116 117 /********************************************************** 118 Indicates connect/disconnect events 119 Parameters: 120 context 121 BOOLEAN bConnected 1/0 connect/disconnect 122 ***********************************************************/ 123 VOID ParaNdis_IndicateConnect(PARANDIS_ADAPTER *pContext, BOOLEAN bConnected, BOOLEAN bForce) 124 { 125 // indicate disconnect always 126 if (bConnected != pContext->bConnected || bForce) 127 { 128 pContext->bConnected = bConnected; 129 DPrintf(0, ("Indicating %sconnect", bConnected ? "" : "dis")); 130 ParaNdis_DebugHistory(pContext, hopConnectIndication, NULL, bConnected, 0, 0); 131 NdisMIndicateStatus( 132 pContext->MiniportHandle, 133 bConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT, 134 0, 135 0); 136 NdisMIndicateStatusComplete(pContext->MiniportHandle); 137 } 138 } 139 140 VOID ParaNdis_SetPowerState(PARANDIS_ADAPTER *pContext, NDIS_DEVICE_POWER_STATE newState) 141 { 142 //NDIS_DEVICE_POWER_STATE prev = pContext->powerState; 143 pContext->powerState = newState; 144 } 145 146 147 /********************************************************** 148 Callback of timer for connect indication, if used 149 Parameters: 150 context (on FunctionContext) 151 all the rest are irrelevant 152 ***********************************************************/ 153 static VOID NTAPI OnConnectTimer( 154 IN PVOID SystemSpecific1, 155 IN PVOID FunctionContext, 156 IN PVOID SystemSpecific2, 157 IN PVOID SystemSpecific3 158 ) 159 { 160 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)FunctionContext; 161 ParaNdis_ReportLinkStatus(pContext, FALSE); 162 } 163 164 /********************************************************** 165 NDIS5 implementation of shared memory allocation 166 Parameters: 167 context 168 tCompletePhysicalAddress *pAddresses 169 the structure accumulates all our knowledge 170 about the allocation (size, addresses, cacheability etc) 171 Return value: 172 TRUE if the allocation was successful 173 ***********************************************************/ 174 BOOLEAN ParaNdis_InitialAllocatePhysicalMemory( 175 PARANDIS_ADAPTER *pContext, 176 tCompletePhysicalAddress *pAddresses) 177 { 178 NdisMAllocateSharedMemory( 179 pContext->MiniportHandle, 180 pAddresses->size, 181 (BOOLEAN)pAddresses->IsCached, 182 &pAddresses->Virtual, 183 &pAddresses->Physical); 184 return pAddresses->Virtual != NULL; 185 } 186 187 /********************************************************** 188 Callback of timer for pending events cleanup after regular DPC processing 189 Parameters: 190 context (on FunctionContext) 191 all the rest are irrelevant 192 ***********************************************************/ 193 static VOID NTAPI OnDPCPostProcessTimer( 194 IN PVOID SystemSpecific1, 195 IN PVOID FunctionContext, 196 IN PVOID SystemSpecific2, 197 IN PVOID SystemSpecific3 198 ) 199 { 200 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)FunctionContext; 201 ULONG requiresProcessing; 202 requiresProcessing = ParaNdis_DPCWorkBody(pContext, PARANDIS_UNLIMITED_PACKETS_TO_INDICATE); 203 if (requiresProcessing) 204 { 205 // we need to request additional DPC 206 InterlockedOr(&pContext->InterruptStatus, requiresProcessing); 207 NdisSetTimer(&pContext->DPCPostProcessTimer, 10); 208 } 209 } 210 211 /********************************************************** 212 NDIS5 implementation of shared memory freeing 213 Parameters: 214 context 215 tCompletePhysicalAddress *pAddresses 216 the structure accumulates all our knowledge 217 about the allocation (size, addresses, cacheability etc) 218 filled by ParaNdis_InitialAllocatePhysicalMemory 219 ***********************************************************/ 220 VOID ParaNdis_FreePhysicalMemory( 221 PARANDIS_ADAPTER *pContext, 222 tCompletePhysicalAddress *pAddresses) 223 { 224 225 NdisMFreeSharedMemory( 226 pContext->MiniportHandle, 227 pAddresses->size, 228 (BOOLEAN)pAddresses->IsCached, 229 pAddresses->Virtual, 230 pAddresses->Physical); 231 } 232 233 static void DebugParseOffloadBits() 234 { 235 NDIS_TCP_IP_CHECKSUM_PACKET_INFO info; 236 tChecksumCheckResult res; 237 ULONG val = 1; 238 int level = 1; 239 while (val) 240 { 241 info.Value = val; 242 if (info.Receive.NdisPacketIpChecksumFailed) DPrintf(level, ("W.%X=IPCS failed", val)); 243 if (info.Receive.NdisPacketIpChecksumSucceeded) DPrintf(level, ("W.%X=IPCS OK", val)); 244 if (info.Receive.NdisPacketTcpChecksumFailed) DPrintf(level, ("W.%X=TCPCS failed", val)); 245 if (info.Receive.NdisPacketTcpChecksumSucceeded) DPrintf(level, ("W.%X=TCPCS OK", val)); 246 if (info.Receive.NdisPacketUdpChecksumFailed) DPrintf(level, ("W.%X=UDPCS failed", val)); 247 if (info.Receive.NdisPacketUdpChecksumSucceeded) DPrintf(level, ("W.%X=UDPCS OK", val)); 248 val = val << 1; 249 } 250 val = 1; 251 while (val) 252 { 253 res.value = val; 254 if (res.flags.IpFailed) DPrintf(level, ("C.%X=IPCS failed", val)); 255 if (res.flags.IpOK) DPrintf(level, ("C.%X=IPCS OK", val)); 256 if (res.flags.TcpFailed) DPrintf(level, ("C.%X=TCPCS failed", val)); 257 if (res.flags.TcpOK) DPrintf(level, ("C.%X=TCPCS OK", val)); 258 if (res.flags.UdpFailed) DPrintf(level, ("C.%X=UDPCS failed", val)); 259 if (res.flags.UdpOK) DPrintf(level, ("C.%X=UDPCS OK", val)); 260 val = val << 1; 261 } 262 } 263 264 /********************************************************** 265 Procedure for NDIS5 specific initialization: 266 register interrupt handler 267 allocate pool of packets to indicate 268 allocate pool of buffers to indicate 269 initialize halt event 270 Parameters: 271 context 272 Return value: 273 SUCCESS or failure code 274 ***********************************************************/ 275 NDIS_STATUS NTAPI ParaNdis_FinishSpecificInitialization( 276 PARANDIS_ADAPTER *pContext) 277 { 278 NDIS_STATUS status; 279 UINT nPackets = pContext->NetMaxReceiveBuffers * 2; 280 DEBUG_ENTRY(2); 281 NdisInitializeEvent(&pContext->HaltEvent); 282 InitializeListHead(&pContext->SendQueue); 283 InitializeListHead(&pContext->TxWaitingList); 284 NdisInitializeTimer(&pContext->ConnectTimer, OnConnectTimer, pContext); 285 NdisInitializeTimer(&pContext->DPCPostProcessTimer, OnDPCPostProcessTimer, pContext); 286 287 status = NdisMRegisterInterrupt( 288 &pContext->Interrupt, 289 pContext->MiniportHandle, 290 pContext->AdapterResources.Vector, 291 pContext->AdapterResources.Level, 292 TRUE, 293 TRUE, 294 NdisInterruptLevelSensitive); 295 296 if (status == NDIS_STATUS_SUCCESS) 297 { 298 NdisAllocatePacketPool( 299 &status, 300 &pContext->PacketPool, 301 nPackets, 302 PROTOCOL_RESERVED_SIZE_IN_PACKET ); 303 } 304 if (status == NDIS_STATUS_SUCCESS) 305 { 306 NdisAllocateBufferPool( 307 &status, 308 &pContext->BuffersPool, 309 nPackets); 310 } 311 312 #if !DO_MAP_REGISTERS 313 if (status == NDIS_STATUS_SUCCESS) 314 { 315 status = NdisMInitializeScatterGatherDma( 316 pContext->MiniportHandle, 317 TRUE, 318 0x10000); 319 pContext->bDmaInitialized = status == NDIS_STATUS_SUCCESS; 320 } 321 #else 322 if (status == NDIS_STATUS_SUCCESS) 323 { 324 status = NdisMAllocateMapRegisters( 325 pContext->MiniportHandle, 326 0, 327 NDIS_DMA_32BITS, 328 64, 329 PAGE_SIZE); 330 pContext->bDmaInitialized = status == NDIS_STATUS_SUCCESS; 331 } 332 #endif 333 if (status == NDIS_STATUS_SUCCESS) 334 { 335 DebugParseOffloadBits(); 336 } 337 DEBUG_EXIT_STATUS(status ? 0 : 2, status); 338 return status; 339 } 340 341 /********************************************************** 342 Procedure of NDIS5-specific cleanup: 343 deregister interrupt 344 free buffer and packet pool 345 Parameters: 346 context 347 ***********************************************************/ 348 VOID ParaNdis_FinalizeCleanup(PARANDIS_ADAPTER *pContext) 349 { 350 if (pContext->Interrupt.InterruptObject) 351 { 352 NdisMDeregisterInterrupt(&pContext->Interrupt); 353 } 354 if (pContext->BuffersPool) 355 { 356 NdisFreeBufferPool(pContext->BuffersPool); 357 } 358 if (pContext->PacketPool) 359 { 360 NdisFreePacketPool(pContext->PacketPool); 361 } 362 #if DO_MAP_REGISTERS 363 if (pContext->bDmaInitialized) 364 { 365 NdisMFreeMapRegisters(pContext->MiniportHandle); 366 } 367 #endif 368 } 369 370 371 static FORCEINLINE ULONG MaxNdisBufferDataSize(PARANDIS_ADAPTER *pContext, pIONetDescriptor pBufferDesc) 372 { 373 ULONG size = pBufferDesc->DataInfo.size; 374 if (pContext->bUseMergedBuffers) size -= pContext->nVirtioHeaderSize; 375 return size; 376 } 377 378 379 /********************************************************** 380 NDIS5-specific procedure for binding RX buffer to 381 NDIS_PACKET and NDIS_BUFFER 382 Parameters: 383 context 384 pIONetDescriptor pBuffersDesc VirtIO buffer descriptor 385 386 Return value: 387 TRUE, if bound successfully 388 FALSE, if no buffer or packet can be allocated 389 ***********************************************************/ 390 BOOLEAN ParaNdis_BindBufferToPacket( 391 PARANDIS_ADAPTER *pContext, 392 pIONetDescriptor pBufferDesc) 393 { 394 NDIS_STATUS status; 395 PNDIS_BUFFER pBuffer = NULL; 396 PNDIS_PACKET Packet = NULL; 397 NdisAllocatePacket(&status, &Packet, pContext->PacketPool); 398 if (status == NDIS_STATUS_SUCCESS) 399 { 400 NdisReinitializePacket(Packet); 401 NdisAllocateBuffer( 402 &status, 403 &pBuffer, 404 pContext->BuffersPool, 405 RtlOffsetToPointer(pBufferDesc->DataInfo.Virtual, pContext->bUseMergedBuffers ? pContext->nVirtioHeaderSize : 0), 406 MaxNdisBufferDataSize(pContext, pBufferDesc)); 407 } 408 if (status == NDIS_STATUS_SUCCESS) 409 { 410 PNDIS_PACKET_OOB_DATA pOOB = NDIS_OOB_DATA_FROM_PACKET(Packet); 411 NdisZeroMemory(pOOB, sizeof(NDIS_PACKET_OOB_DATA)); 412 NDIS_SET_PACKET_HEADER_SIZE(Packet, ETH_HEADER_SIZE); 413 NdisChainBufferAtFront(Packet, pBuffer); 414 pBufferDesc->pHolder = Packet; 415 } 416 else 417 { 418 if (pBuffer) NdisFreeBuffer(pBuffer); 419 if (Packet) NdisFreePacket(Packet); 420 } 421 return status == NDIS_STATUS_SUCCESS; 422 } 423 424 425 /********************************************************** 426 NDIS5-specific procedure for unbinding 427 previously bound RX buffer from it's NDIS_PACKET and NDIS_BUFFER 428 Parameters: 429 context 430 pIONetDescriptor pBuffersDesc VirtIO buffer descriptor 431 ***********************************************************/ 432 void ParaNdis_UnbindBufferFromPacket( 433 PARANDIS_ADAPTER *pContext, 434 pIONetDescriptor pBufferDesc) 435 { 436 if (pBufferDesc->pHolder) 437 { 438 PNDIS_BUFFER pBuffer = NULL; 439 PNDIS_PACKET Packet = pBufferDesc->pHolder; 440 pBufferDesc->pHolder = NULL; 441 NdisUnchainBufferAtFront(Packet, &pBuffer); 442 if (pBuffer) 443 { 444 NdisAdjustBufferLength(pBuffer, MaxNdisBufferDataSize(pContext, pBufferDesc)); 445 NdisFreeBuffer(pBuffer); 446 } 447 NdisFreePacket(Packet); 448 } 449 } 450 451 /********************************************************** 452 NDIS5-specific procedure to indicate received packets 453 454 Parameters: 455 context 456 pIONetDescriptor pBuffersDescriptor - VirtIO buffer descriptor of data buffer 457 PVOID dataBuffer - data buffer to pass to network stack 458 PULONG pLength - size of received packet. 459 BOOLEAN bPrepareOnly - only return NBL for further indication in batch 460 Return value: 461 TRUE is packet indicated 462 FALSE if not (in this case, the descriptor should be freed now) 463 If priority header is in the packet. it will be removed and *pLength decreased 464 ***********************************************************/ 465 tPacketIndicationType ParaNdis_IndicateReceivedPacket( 466 PARANDIS_ADAPTER *pContext, 467 PVOID dataBuffer, 468 PULONG pLength, 469 BOOLEAN bPrepareOnly, 470 pIONetDescriptor pBuffersDesc) 471 { 472 PNDIS_BUFFER pBuffer = NULL; 473 PNDIS_BUFFER pNoBuffer = NULL; 474 PNDIS_PACKET Packet = pBuffersDesc->pHolder; 475 ULONG length = *pLength; 476 if (Packet) NdisUnchainBufferAtFront(Packet, &pBuffer); 477 if (Packet) NdisUnchainBufferAtFront(Packet, &pNoBuffer); 478 if (pBuffer) 479 { 480 UINT uTotalLength; 481 NDIS_PACKET_8021Q_INFO qInfo; 482 qInfo.Value = NULL; 483 if ((pContext->ulPriorityVlanSetting && length > (ETH_PRIORITY_HEADER_OFFSET + ETH_PRIORITY_HEADER_SIZE)) || 484 length > pContext->MaxPacketSize.nMaxFullSizeOS) 485 { 486 PUCHAR pPriority = (PUCHAR)dataBuffer + ETH_PRIORITY_HEADER_OFFSET; 487 if (ETH_HAS_PRIO_HEADER(dataBuffer)) 488 { 489 if (IsPrioritySupported(pContext)) 490 qInfo.TagHeader.UserPriority = (pPriority[2] & 0xE0) >> 5; 491 if (IsVlanSupported(pContext)) 492 { 493 qInfo.TagHeader.VlanId = (((USHORT)(pPriority[2] & 0x0F)) << 8) | pPriority[3]; 494 if (pContext->VlanId && pContext->VlanId != qInfo.TagHeader.VlanId) 495 { 496 DPrintf(0, ("[%s] Failing unexpected VlanID %d", __FUNCTION__, qInfo.TagHeader.VlanId)); 497 pContext->extraStatistics.framesFilteredOut++; 498 pBuffer = NULL; 499 } 500 } 501 RtlMoveMemory( 502 pPriority, 503 pPriority + ETH_PRIORITY_HEADER_SIZE, 504 length - ETH_PRIORITY_HEADER_OFFSET - ETH_PRIORITY_HEADER_SIZE); 505 length -= ETH_PRIORITY_HEADER_SIZE; 506 if (length > pContext->MaxPacketSize.nMaxFullSizeOS) 507 { 508 DPrintf(0, ("[%s] Can not indicate up packet of %d", __FUNCTION__, length)); 509 pBuffer = NULL; 510 } 511 DPrintf(1, ("[%s] Found priority data %p", __FUNCTION__, qInfo.Value)); 512 pContext->extraStatistics.framesRxPriority++; 513 } 514 } 515 516 if (pBuffer) 517 { 518 PVOID headerBuffer = pContext->bUseMergedBuffers ? pBuffersDesc->DataInfo.Virtual:pBuffersDesc->HeaderInfo.Virtual; 519 virtio_net_hdr_basic *pHeader = (virtio_net_hdr_basic *)headerBuffer; 520 tChecksumCheckResult csRes; 521 NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo) = qInfo.Value; 522 NDIS_SET_PACKET_STATUS(Packet, STATUS_SUCCESS); 523 ParaNdis_PadPacketReceived(dataBuffer, &length); 524 NdisAdjustBufferLength(pBuffer, length); 525 NdisChainBufferAtFront(Packet, pBuffer); 526 NdisQueryPacket(Packet, NULL, NULL, NULL, &uTotalLength); 527 *REF_MINIPORT(Packet) = pBuffersDesc; 528 csRes = ParaNdis_CheckRxChecksum(pContext, pHeader->flags, dataBuffer, length); 529 if (csRes.value) 530 { 531 NDIS_TCP_IP_CHECKSUM_PACKET_INFO qCSInfo; 532 qCSInfo.Value = 0; 533 qCSInfo.Receive.NdisPacketIpChecksumFailed = csRes.flags.IpFailed; 534 qCSInfo.Receive.NdisPacketIpChecksumSucceeded = csRes.flags.IpOK; 535 qCSInfo.Receive.NdisPacketTcpChecksumFailed = csRes.flags.TcpFailed; 536 qCSInfo.Receive.NdisPacketTcpChecksumSucceeded = csRes.flags.TcpOK; 537 qCSInfo.Receive.NdisPacketUdpChecksumFailed = csRes.flags.UdpFailed; 538 qCSInfo.Receive.NdisPacketUdpChecksumSucceeded = csRes.flags.UdpOK; 539 NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpIpChecksumPacketInfo) = (PVOID) (ULONG_PTR) qCSInfo.Value; 540 DPrintf(1, ("Reporting CS %X->%X", csRes.value, qCSInfo.Value)); 541 } 542 543 DPrintf(4, ("[%s] buffer %p(%d b.)", __FUNCTION__, pBuffersDesc, length)); 544 if (!bPrepareOnly) 545 { 546 NdisMIndicateReceivePacket( 547 pContext->MiniportHandle, 548 &Packet, 549 1); 550 } 551 } 552 *pLength = length; 553 } 554 if (!pBuffer) 555 { 556 DPrintf(0, ("[%s] Error: %p(%d b.) with packet %p", __FUNCTION__, 557 pBuffersDesc, length, Packet)); 558 Packet = NULL; 559 } 560 if (pNoBuffer) 561 { 562 DPrintf(0, ("[%s] Error: %p(%d b.) with packet %p, buf %p,%p", __FUNCTION__, 563 pBuffersDesc, length, Packet, pBuffer, pNoBuffer)); 564 } 565 return Packet; 566 } 567 568 VOID ParaNdis_IndicateReceivedBatch( 569 PARANDIS_ADAPTER *pContext, 570 tPacketIndicationType *pBatch, 571 ULONG nofPackets) 572 { 573 NdisMIndicateReceivePacket( 574 pContext->MiniportHandle, 575 pBatch, 576 nofPackets); 577 } 578 579 static FORCEINLINE void GET_NUMBER_OF_SG_ELEMENTS(PNDIS_PACKET Packet, UINT *pNum) 580 { 581 PSCATTER_GATHER_LIST pSGList; 582 pSGList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo); 583 if (pSGList) 584 { 585 *pNum = pSGList->NumberOfElements; 586 } 587 } 588 589 /********************************************************** 590 Complete TX packets to NDIS with status, indicated inside packet 591 Parameters: 592 context 593 PNDIS_PACKET Packet packet to complete 594 ***********************************************************/ 595 static void CompletePacket(PARANDIS_ADAPTER *pContext, PNDIS_PACKET Packet) 596 { 597 LONG lRestToReturn; 598 NDIS_STATUS status = NDIS_GET_PACKET_STATUS(Packet); 599 lRestToReturn = NdisInterlockedDecrement(&pContext->NetTxPacketsToReturn); 600 ParaNdis_DebugHistory(pContext, hopSendComplete, Packet, 0, lRestToReturn, status); 601 NdisMSendComplete(pContext->MiniportHandle, Packet, status); 602 } 603 604 /********************************************************** 605 Copy data from specified packet to VirtIO buffer, minimum 60 bytes 606 Parameters: 607 PNDIS_PACKET Packet packet to copy data from 608 PVOID dest destination to copy 609 ULONG maxSize maximal size of destination 610 Return value: 611 size = number of bytes copied 612 if 0, the packet is not transmitted and should be dropped 613 ( should never happen) 614 request 615 ***********************************************************/ 616 tCopyPacketResult ParaNdis_PacketCopier( 617 PNDIS_PACKET Packet, PVOID dest, ULONG maxSize, PVOID refValue, BOOLEAN bPreview) 618 { 619 PNDIS_BUFFER pBuffer; 620 ULONG PriorityDataLong = ((tSendEntry *)refValue)->PriorityDataLong; 621 tCopyPacketResult result; 622 /* the copier called also for getting Ethernet header 623 for statistics, when the transfer uses SG table */ 624 UINT uLength = 0; 625 ULONG nCopied = 0; 626 ULONG ulToCopy = 0; 627 if (bPreview) PriorityDataLong = 0; 628 NdisQueryPacket(Packet, 629 NULL, 630 NULL, 631 &pBuffer, 632 (PUINT)&ulToCopy); 633 634 if (ulToCopy > maxSize) ulToCopy = bPreview ? maxSize : 0; 635 while (pBuffer && ulToCopy) 636 { 637 PVOID VirtualAddress = NULL; 638 NdisQueryBufferSafe(pBuffer, 639 &VirtualAddress, 640 &uLength, 641 NormalPagePriority); 642 if (!VirtualAddress) 643 { 644 /* the packet copy failed */ 645 nCopied = 0; 646 break; 647 } 648 if(uLength) 649 { 650 // Copy the data. 651 if (uLength > ulToCopy) uLength = ulToCopy; 652 ulToCopy -= uLength; 653 if ((PriorityDataLong & 0xFFFF) && 654 nCopied < ETH_PRIORITY_HEADER_OFFSET && 655 (nCopied + uLength) >= ETH_PRIORITY_HEADER_OFFSET) 656 { 657 ULONG ulCopyNow = ETH_PRIORITY_HEADER_OFFSET - nCopied; 658 NdisMoveMemory(dest, VirtualAddress, ulCopyNow); 659 dest = (PUCHAR)dest + ulCopyNow; 660 VirtualAddress = (PUCHAR)VirtualAddress + ulCopyNow; 661 NdisMoveMemory(dest, &PriorityDataLong, 4); 662 nCopied += 4; 663 dest = (PCHAR)dest + 4; 664 ulCopyNow = uLength - ulCopyNow; 665 if (ulCopyNow) NdisMoveMemory(dest, VirtualAddress, ulCopyNow); 666 dest = (PCHAR)dest + ulCopyNow; 667 nCopied += uLength; 668 } 669 else 670 { 671 NdisMoveMemory(dest, VirtualAddress, uLength); 672 nCopied += uLength; 673 dest = (PUCHAR)dest + uLength; 674 } 675 } 676 NdisGetNextBuffer(pBuffer, &pBuffer); 677 } 678 679 DEBUG_EXIT_STATUS(4, nCopied); 680 result.size = nCopied; 681 return result; 682 } 683 684 685 /********************************************************** 686 Callback on finished Tx descriptor 687 ***********************************************************/ 688 VOID ParaNdis_OnTransmitBufferReleased(PARANDIS_ADAPTER *pContext, IONetDescriptor *pDesc) 689 { 690 tSendEntry *pEntry = (tSendEntry *)pDesc->ReferenceValue; 691 if (pEntry) 692 { 693 DPrintf(2, ("[%s] Entry %p (packet %p, %d buffers) ready!", __FUNCTION__, pEntry, pEntry->packet, pDesc->nofUsedBuffers)); 694 pEntry->flags |= SEND_ENTRY_FLAG_READY; 695 pDesc->ReferenceValue = NULL; 696 ParaNdis_DebugHistory(pContext, hopBufferSent, pEntry->packet, 0, pContext->nofFreeHardwareBuffers, pContext->nofFreeTxDescriptors); 697 } 698 else 699 { 700 ParaNdis_DebugHistory(pContext, hopBufferSent, NULL, 0, pContext->nofFreeHardwareBuffers, pContext->nofFreeTxDescriptors); 701 DPrintf(0, ("[%s] ERROR: Send Entry not set!", __FUNCTION__)); 702 } 703 } 704 705 706 static FORCEINLINE ULONG CalculateTotalOffloadSize( 707 ULONG packetSize, 708 ULONG mss, 709 ULONG ipheaderOffset, 710 ULONG maxPossiblePacketSize, 711 tTcpIpPacketParsingResult packetReview) 712 { 713 ULONG ul = 0; 714 ULONG tcpipHeaders = packetReview.XxpIpHeaderSize; 715 ULONG allHeaders = tcpipHeaders + ipheaderOffset; 716 if (tcpipHeaders && (mss + allHeaders) <= maxPossiblePacketSize) 717 { 718 ULONG nFragments = (packetSize - allHeaders)/mss; 719 ULONG last = (packetSize - allHeaders)%mss; 720 ul = nFragments * (mss + allHeaders) + last + (last ? allHeaders : 0); 721 } 722 DPrintf(1, ("[%s]%s %d/%d, headers %d)", 723 __FUNCTION__, !ul ? "ERROR:" : "", ul, mss, allHeaders)); 724 return ul; 725 } 726 727 /********************************************************** 728 Maps the HW buffers of the packet into entries of VirtIO queue 729 Parameters: 730 miniport context 731 PNDIS_PACKET Packet packet to copy data from 732 PVOID ReferenceValue - tSendEntry * of the packet 733 VirtIOBufferDescriptor buffers = array of buffers to map packet buffers 734 (it contains number of SG entries >= number of hw elements in the packet) 735 pIONetDescriptor pDesc - holder of VirtIO header and reserved data buffer 736 for possible replacement of one or more HW buffers 737 738 Returns @pMapperResult: (zeroed before call) 739 .usBuffersMapped - number of buffers mapped (one of them may be our own) 740 .ulDataSize - number of bytes to report as transmitted (802.1P tag is not counted) 741 .usBufferSpaceUsed - number of bytes used in data space of pIONetDescriptor pDesc 742 ***********************************************************/ 743 VOID ParaNdis_PacketMapper( 744 PARANDIS_ADAPTER *pContext, 745 PNDIS_PACKET packet, 746 PVOID ReferenceValue, 747 struct VirtIOBufferDescriptor *buffers, 748 pIONetDescriptor pDesc, 749 tMapperResult *pMapperResult) 750 { 751 tSendEntry *pSendEntry = (tSendEntry *)ReferenceValue; 752 ULONG PriorityDataLong = pSendEntry->PriorityDataLong; 753 PSCATTER_GATHER_LIST pSGList = NDIS_PER_PACKET_INFO_FROM_PACKET(packet, ScatterGatherListPacketInfo); 754 SCATTER_GATHER_ELEMENT *pSGElements = pSGList->Elements; 755 756 757 if (pSGList && pSGList->NumberOfElements) 758 { 759 UINT i, lengthGet = 0, lengthPut = 0, nCompleteBuffersToSkip = 0, nBytesSkipInFirstBuffer = 0; 760 if (pSendEntry->flags & (SEND_ENTRY_TSO_USED | SEND_ENTRY_TCP_CS | SEND_ENTRY_UDP_CS | SEND_ENTRY_IP_CS)) 761 lengthGet = pContext->Offload.ipHeaderOffset + MAX_IPV4_HEADER_SIZE + sizeof(TCPHeader); 762 if (PriorityDataLong && !lengthGet) 763 lengthGet = ETH_HEADER_SIZE; 764 if (lengthGet) 765 { 766 ULONG len = 0; 767 for (i = 0; i < pSGList->NumberOfElements; ++i) 768 { 769 len += pSGElements[i].Length; 770 if (len > lengthGet) 771 { 772 nBytesSkipInFirstBuffer = pSGList->Elements[i].Length - (len - lengthGet); 773 break; 774 } 775 DPrintf(2, ("[%s] skipping buffer %d of %d", __FUNCTION__, nCompleteBuffersToSkip, pSGElements[i].Length)); 776 nCompleteBuffersToSkip++; 777 } 778 // just for case of UDP packet shorter than TCP header 779 if (lengthGet > len) lengthGet = len; 780 lengthPut = lengthGet + (PriorityDataLong ? ETH_PRIORITY_HEADER_SIZE : 0); 781 } 782 783 if (lengthPut > pDesc->DataInfo.size) 784 { 785 DPrintf(0, ("[%s] ERROR: can not substitute %d bytes, sending as is", __FUNCTION__, lengthPut)); 786 nCompleteBuffersToSkip = 0; 787 nBytesSkipInFirstBuffer = 0; 788 lengthGet = lengthPut = 0; 789 } 790 791 if (lengthPut) 792 { 793 // we replace 1 or more HW buffers with one buffer preallocated for data 794 buffers->physAddr = pDesc->DataInfo.Physical; 795 buffers->length = lengthPut; 796 pMapperResult->usBufferSpaceUsed = (USHORT)lengthPut; 797 pMapperResult->ulDataSize += lengthGet; 798 pMapperResult->usBuffersMapped = (USHORT)(pSGList->NumberOfElements - nCompleteBuffersToSkip + 1); 799 pSGElements += nCompleteBuffersToSkip; 800 buffers++; 801 DPrintf(1, ("[%s](%d bufs) skip %d buffers + %d bytes", 802 __FUNCTION__, pSGList->NumberOfElements, nCompleteBuffersToSkip, nBytesSkipInFirstBuffer)); 803 } 804 else 805 { 806 pMapperResult->usBuffersMapped = (USHORT)pSGList->NumberOfElements; 807 } 808 809 for (i = nCompleteBuffersToSkip; i < pSGList->NumberOfElements; ++i) 810 { 811 if (nBytesSkipInFirstBuffer) 812 { 813 buffers->physAddr.QuadPart = pSGElements->Address.QuadPart + nBytesSkipInFirstBuffer; 814 buffers->length = pSGElements->Length - nBytesSkipInFirstBuffer; 815 DPrintf(2, ("[%s] using HW buffer %d of %d-%d", __FUNCTION__, i, pSGElements->Length, nBytesSkipInFirstBuffer)); 816 nBytesSkipInFirstBuffer = 0; 817 } 818 else 819 { 820 buffers->physAddr = pSGElements->Address; 821 buffers->length = pSGElements->Length; 822 } 823 pMapperResult->ulDataSize += buffers->length; 824 pSGElements++; 825 buffers++; 826 } 827 828 if (lengthPut) 829 { 830 PVOID pBuffer = pDesc->DataInfo.Virtual; 831 PVOID pIpHeader = RtlOffsetToPointer(pBuffer, pContext->Offload.ipHeaderOffset); 832 ParaNdis_PacketCopier(packet, pBuffer, lengthGet, ReferenceValue, TRUE); 833 834 if (pSendEntry->flags & SEND_ENTRY_TSO_USED) 835 { 836 tTcpIpPacketParsingResult packetReview; 837 ULONG dummyTransferSize = 0; 838 USHORT saveBuffers = pMapperResult->usBuffersMapped; 839 ULONG flags = pcrIpChecksum | pcrTcpChecksum | pcrFixIPChecksum | pcrFixPHChecksum; 840 pMapperResult->usBuffersMapped = 0; 841 packetReview = ParaNdis_CheckSumVerify( 842 pIpHeader, 843 lengthGet - pContext->Offload.ipHeaderOffset, 844 flags, 845 __FUNCTION__); 846 /* uncomment to verify */ 847 /* 848 packetReview = ParaNdis_CheckSumVerify( 849 pIpHeader, 850 lengthGet - pContext->Offload.ipHeaderOffset, 851 pcrIpChecksum | pcrTcpChecksum, 852 __FUNCTION__); 853 */ 854 if (packetReview.ipCheckSum == ppresCSOK || packetReview.fixedIpCS) 855 { 856 dummyTransferSize = CalculateTotalOffloadSize( 857 pMapperResult->ulDataSize, 858 pSendEntry->ipTransferUnit, 859 pContext->Offload.ipHeaderOffset, 860 pContext->MaxPacketSize.nMaxFullSizeOS, 861 packetReview); 862 } 863 else 864 { 865 DPrintf(0, ("[%s] ERROR locating IP header in %d bytes(IP header of %d)", __FUNCTION__, 866 lengthGet, packetReview.ipHeaderSize)); 867 } 868 NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpLargeSendPacketInfo) = (PVOID)(ULONG_PTR)dummyTransferSize; 869 if (dummyTransferSize) 870 { 871 virtio_net_hdr_basic *pheader = pDesc->HeaderInfo.Virtual; 872 unsigned short addPriorityLen = PriorityDataLong ? ETH_PRIORITY_HEADER_SIZE : 0; 873 pheader->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 874 pheader->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 875 pheader->hdr_len = (USHORT)(packetReview.XxpIpHeaderSize + pContext->Offload.ipHeaderOffset) + addPriorityLen; 876 pheader->gso_size = (USHORT)pSendEntry->ipTransferUnit; 877 pheader->csum_start = (USHORT)pContext->Offload.ipHeaderOffset + (USHORT)packetReview.ipHeaderSize + addPriorityLen; 878 pheader->csum_offset = TCP_CHECKSUM_OFFSET; 879 pMapperResult->usBuffersMapped = saveBuffers; 880 } 881 } 882 else if (pSendEntry->flags & SEND_ENTRY_IP_CS) 883 { 884 ParaNdis_CheckSumVerify( 885 pIpHeader, 886 lengthGet - pContext->Offload.ipHeaderOffset, 887 pcrIpChecksum | pcrFixIPChecksum, 888 __FUNCTION__); 889 } 890 891 if (PriorityDataLong && pMapperResult->usBuffersMapped) 892 { 893 RtlMoveMemory( 894 RtlOffsetToPointer(pBuffer, ETH_PRIORITY_HEADER_OFFSET + ETH_PRIORITY_HEADER_SIZE), 895 RtlOffsetToPointer(pBuffer, ETH_PRIORITY_HEADER_OFFSET), 896 lengthGet - ETH_PRIORITY_HEADER_OFFSET 897 ); 898 NdisMoveMemory( 899 RtlOffsetToPointer(pBuffer, ETH_PRIORITY_HEADER_OFFSET), 900 &PriorityDataLong, 901 sizeof(ETH_PRIORITY_HEADER_SIZE)); 902 DPrintf(1, ("[%s] Populated priority value %lX", __FUNCTION__, PriorityDataLong)); 903 } 904 } 905 } 906 907 } 908 909 static void InitializeTransferParameters(tTxOperationParameters *pParams, tSendEntry *pEntry) 910 { 911 ULONG flags = (pEntry->flags & SEND_ENTRY_TSO_USED) ? pcrLSO : 0; 912 if (pEntry->flags & SEND_ENTRY_NO_INDIRECT) flags |= pcrNoIndirect; 913 NdisQueryPacket(pEntry->packet, &pParams->nofSGFragments, NULL, NULL, (PUINT)&pParams->ulDataSize); 914 pParams->ReferenceValue = pEntry; 915 pParams->packet = pEntry->packet; 916 pParams->offloadMss = (pEntry->flags & SEND_ENTRY_TSO_USED) ? pEntry->ipTransferUnit : 0; 917 // on NDIS5 it is unknown 918 pParams->tcpHeaderOffset = 0; 919 // fills only if SGList present in the packet 920 GET_NUMBER_OF_SG_ELEMENTS(pEntry->packet, &pParams->nofSGFragments); 921 if (NDIS_GET_PACKET_PROTOCOL_TYPE(pEntry->packet) == NDIS_PROTOCOL_ID_TCP_IP) 922 { 923 flags |= pcrIsIP; 924 if (pEntry->flags & SEND_ENTRY_TCP_CS) 925 { 926 flags |= pcrTcpChecksum; 927 } 928 if (pEntry->flags & SEND_ENTRY_UDP_CS) 929 { 930 flags |= pcrUdpChecksum; 931 } 932 if (pEntry->flags & SEND_ENTRY_IP_CS) 933 { 934 flags |= pcrIpChecksum; 935 } 936 } 937 if (pEntry->PriorityDataLong) flags |= pcrPriorityTag; 938 pParams->flags = flags; 939 } 940 941 BOOLEAN ParaNdis_ProcessTx( 942 PARANDIS_ADAPTER *pContext, 943 BOOLEAN IsDpc, 944 BOOLEAN IsInterrupt) 945 { 946 LIST_ENTRY DoneList; 947 BOOLEAN bDoKick = FALSE; 948 UINT nBuffersSent = 0, nBytesSent = 0; 949 BOOLEAN bDataAvailable = FALSE; 950 tSendEntry *pEntry; 951 ONPAUSECOMPLETEPROC CallbackToCall = NULL; 952 InitializeListHead(&DoneList); 953 UNREFERENCED_PARAMETER(IsDpc); 954 NdisAcquireSpinLock(&pContext->SendLock); 955 956 ParaNdis_DebugHistory(pContext, hopTxProcess, NULL, 1, pContext->nofFreeHardwareBuffers, pContext->nofFreeTxDescriptors); 957 do 958 { 959 if(IsTimeToReleaseTx(pContext)) 960 { 961 // release some buffers 962 ParaNdis_VirtIONetReleaseTransmitBuffers(pContext); 963 } 964 pEntry = NULL; 965 if (!IsListEmpty(&pContext->SendQueue)) 966 { 967 tCopyPacketResult result; 968 tTxOperationParameters Params; 969 pEntry = (tSendEntry *)RemoveHeadList(&pContext->SendQueue); 970 InitializeTransferParameters(&Params, pEntry); 971 bDataAvailable = TRUE; 972 result = ParaNdis_DoSubmitPacket(pContext, &Params); 973 if (result.error == cpeNoBuffer) 974 { 975 // can not send now, try next time 976 InsertHeadList(&pContext->SendQueue, &pEntry->list); 977 pEntry = NULL; 978 } 979 else if (result.error == cpeNoIndirect) 980 { 981 InsertHeadList(&pContext->SendQueue, &pEntry->list); 982 pEntry->flags |= SEND_ENTRY_NO_INDIRECT; 983 } 984 else 985 { 986 InsertTailList(&pContext->TxWaitingList, &pEntry->list); 987 ParaNdis_DebugHistory(pContext, hopSubmittedPacket, pEntry->packet, 0, result.error, Params.flags); 988 if (!result.size) 989 { 990 NDIS_STATUS status = NDIS_STATUS_FAILURE; 991 DPrintf(0, ("[%s] ERROR %d copying packet!", __FUNCTION__, result.error)); 992 if (result.error == cpeTooLarge) 993 { 994 status = NDIS_STATUS_BUFFER_OVERFLOW; 995 pContext->Statistics.ifOutErrors++; 996 } 997 NDIS_SET_PACKET_STATUS(pEntry->packet, status); 998 pEntry->flags |= SEND_ENTRY_FLAG_READY; 999 // do not worry, go to the next one 1000 1001 } 1002 else 1003 { 1004 nBuffersSent++; 1005 nBytesSent += result.size; 1006 DPrintf(2, ("[%s] Scheduled packet %p, entry %p(%d bytes)!", __FUNCTION__, 1007 pEntry->packet, pEntry, result.size)); 1008 } 1009 } 1010 } 1011 } while (pEntry); 1012 1013 if (nBuffersSent) 1014 { 1015 if(IsInterrupt) 1016 { 1017 bDoKick = TRUE; 1018 } 1019 else 1020 { 1021 #ifdef PARANDIS_TEST_TX_KICK_ALWAYS 1022 virtqueue_kick_always(pContext->NetSendQueue); 1023 #else 1024 virtqueue_kick(pContext->NetSendQueue); 1025 #endif 1026 } 1027 DPrintf(2, ("[%s] sent down %d p.(%d b.)", __FUNCTION__, nBuffersSent, nBytesSent)); 1028 } 1029 else if (bDataAvailable) 1030 { 1031 DPrintf(2, ("[%s] nothing sent", __FUNCTION__)); 1032 } 1033 1034 /* now check the waiting list of packets */ 1035 while (!IsListEmpty(&pContext->TxWaitingList)) 1036 { 1037 pEntry = (tSendEntry *)RemoveHeadList(&pContext->TxWaitingList); 1038 if (pEntry->flags & SEND_ENTRY_FLAG_READY) 1039 { 1040 InsertTailList(&DoneList, &pEntry->list); 1041 } 1042 else 1043 { 1044 InsertHeadList(&pContext->TxWaitingList, &pEntry->list); 1045 break; 1046 } 1047 } 1048 1049 if (IsListEmpty(&pContext->TxWaitingList) && pContext->SendState == srsPausing && pContext->SendPauseCompletionProc) 1050 { 1051 CallbackToCall = pContext->SendPauseCompletionProc; 1052 pContext->SendPauseCompletionProc = NULL; 1053 pContext->SendState = srsDisabled; 1054 ParaNdis_DebugHistory(pContext, hopInternalSendPause, NULL, 0, 0, 0); 1055 } 1056 NdisReleaseSpinLock(&pContext->SendLock); 1057 1058 while (!IsListEmpty(&DoneList)) 1059 { 1060 pEntry = (tSendEntry *)RemoveHeadList(&DoneList); 1061 CompletePacket(pContext, pEntry->packet); 1062 NdisFreeMemory(pEntry, 0, 0); 1063 } 1064 if (CallbackToCall) CallbackToCall(pContext); 1065 1066 return bDoKick; 1067 } 1068 1069 /********************************************************** 1070 NDIS releases packets previously indicated by miniport 1071 Free the packet's buffer and the packet back to their pools 1072 Returns VirtIO buffer back to queue of free blocks 1073 Parameters: 1074 context 1075 IN PNDIS_PACKET Packet returned packet 1076 ***********************************************************/ 1077 VOID NTAPI ParaNdis5_ReturnPacket(IN NDIS_HANDLE MiniportAdapterContext,IN PNDIS_PACKET Packet) 1078 { 1079 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 1080 pIONetDescriptor pBufferDescriptor; 1081 pBufferDescriptor = (pIONetDescriptor) *REF_MINIPORT(Packet); 1082 DPrintf(4, ("[%s] buffer %p", __FUNCTION__, pBufferDescriptor)); 1083 1084 NdisAcquireSpinLock(&pContext->ReceiveLock); 1085 pContext->ReuseBufferProc(pContext, pBufferDescriptor); 1086 NdisReleaseSpinLock(&pContext->ReceiveLock); 1087 } 1088 1089 static __inline tSendEntry * PrepareSendEntry(PARANDIS_ADAPTER *pContext, PNDIS_PACKET Packet, ULONG len) 1090 { 1091 ULONG mss = (ULONG)(ULONG_PTR)NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo); 1092 UINT protocol = NDIS_GET_PACKET_PROTOCOL_TYPE(Packet); 1093 LPCSTR errorFmt = NULL; 1094 LPCSTR offloadName = "NO offload"; 1095 tSendEntry *pse = (tSendEntry *)ParaNdis_AllocateMemory(pContext, sizeof(tSendEntry)); 1096 if (pse) 1097 { 1098 NDIS_PACKET_8021Q_INFO qInfo; 1099 pse->packet = Packet; 1100 pse->flags = 0; 1101 pse->PriorityDataLong = 0; 1102 pse->ipTransferUnit = len; 1103 //pse->fullTCPCheckSum = 0; 1104 qInfo.Value = pContext->ulPriorityVlanSetting ? 1105 NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, Ieee8021QInfo) : NULL; 1106 if (!qInfo.TagHeader.VlanId) qInfo.TagHeader.VlanId = pContext->VlanId; 1107 if (qInfo.TagHeader.CanonicalFormatId || !IsValidVlanId(pContext, qInfo.TagHeader.VlanId)) 1108 { 1109 DPrintf(0, ("[%s] Discarding priority tag %p", __FUNCTION__, qInfo.Value)); 1110 errorFmt = "invalid priority tag"; 1111 } 1112 else if (qInfo.Value) 1113 { 1114 // ignore priority, if configured 1115 if (!IsPrioritySupported(pContext)) 1116 qInfo.TagHeader.UserPriority = 0; 1117 // ignore VlanId, if specified 1118 if (!IsVlanSupported(pContext)) 1119 qInfo.TagHeader.VlanId = 0; 1120 SetPriorityData(pse->PriorityData, qInfo.TagHeader.UserPriority, qInfo.TagHeader.VlanId); 1121 DPrintf(1, ("[%s] Populated priority tag %p", __FUNCTION__, qInfo.Value)); 1122 } 1123 1124 if (!errorFmt && !mss && len > pContext->MaxPacketSize.nMaxFullSizeOS) 1125 { 1126 DPrintf(0, ("[%s] Request for offload with NO MSS, lso %d, ipheader %d", 1127 __FUNCTION__, pContext->Offload.flags.fTxLso, pContext->Offload.ipHeaderOffset)); 1128 if (pContext->Offload.flags.fTxLso && pContext->Offload.ipHeaderOffset) 1129 { 1130 mss = pContext->MaxPacketSize.nMaxFullSizeOS; 1131 } 1132 else 1133 errorFmt = "illegal LSO request"; 1134 } 1135 1136 if (errorFmt) 1137 { 1138 // already failed 1139 } 1140 else if (mss > pContext->MaxPacketSize.nMaxFullSizeOS) 1141 errorFmt = "mss is too big"; 1142 else if (len > 0xFFFF) 1143 errorFmt = "packet is bigger than we able to send"; 1144 else if (mss && pContext->Offload.flags.fTxLso) 1145 { 1146 offloadName = "LSO"; 1147 pse->ipTransferUnit = mss; 1148 pse->flags |= SEND_ENTRY_TSO_USED; 1149 // todo: move to common space 1150 // to transmit 'len' with 'mss' we usually need 2 additional buffers 1151 if ((len / mss + 3) > pContext->maxFreeHardwareBuffers) 1152 errorFmt = "packet too big to fragment"; 1153 else if (len < pContext->Offload.ipHeaderOffset) 1154 errorFmt = "ip offset is bigger than packet"; 1155 else if (protocol != NDIS_PROTOCOL_ID_TCP_IP) 1156 errorFmt = "attempt to offload non-IP packet"; 1157 else if (mss < pContext->Offload.ipHeaderOffset) 1158 errorFmt = "mss is too small"; 1159 } 1160 else 1161 { 1162 // unexpected CS requests we do not fail - WHQL expects us to send them as is 1163 NDIS_TCP_IP_CHECKSUM_PACKET_INFO csInfo; 1164 csInfo.Value = (ULONG)(ULONG_PTR)NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpIpChecksumPacketInfo); 1165 if (csInfo.Transmit.NdisPacketChecksumV4) 1166 { 1167 if (csInfo.Transmit.NdisPacketTcpChecksum) 1168 { 1169 offloadName = "TCP CS"; 1170 if (pContext->Offload.flags.fTxTCPChecksum) 1171 pse->flags |= SEND_ENTRY_TCP_CS; 1172 else 1173 errorFmt = "TCP CS requested but not enabled"; 1174 } 1175 if (csInfo.Transmit.NdisPacketUdpChecksum) 1176 { 1177 offloadName = "UDP CS"; 1178 if (pContext->Offload.flags.fTxUDPChecksum) 1179 pse->flags |= SEND_ENTRY_UDP_CS; 1180 else 1181 errorFmt = "UDP CS requested but not enabled"; 1182 } 1183 if (csInfo.Transmit.NdisPacketIpChecksum) 1184 { 1185 if (pContext->Offload.flags.fTxIPChecksum) 1186 pse->flags |= SEND_ENTRY_IP_CS; 1187 else 1188 errorFmt = "IP CS requested but not enabled"; 1189 } 1190 if (errorFmt) 1191 { 1192 DPrintf(0, ("[%s] ERROR: %s (len %d)", __FUNCTION__, errorFmt, len)); 1193 errorFmt = NULL; 1194 } 1195 } 1196 } 1197 } 1198 1199 if (errorFmt) 1200 { 1201 DPrintf(0, ("[%s] ERROR: %s (len %d, mss %d)", __FUNCTION__, errorFmt, len, mss)); 1202 if (pse) NdisFreeMemory(pse, 0, 0); 1203 pse = NULL; 1204 } 1205 else 1206 { 1207 NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo) = (PVOID)(ULONG_PTR)0; 1208 DPrintf(1, ("[%s] Sending packet of %d with %s", __FUNCTION__, len, offloadName)); 1209 if (pContext->bDoIPCheckTx) 1210 { 1211 tTcpIpPacketParsingResult res; 1212 VOID *pcopy = ParaNdis_AllocateMemory(pContext, len); 1213 ParaNdis_PacketCopier(pse->packet, pcopy, len, pse, TRUE); 1214 res = ParaNdis_CheckSumVerify( 1215 RtlOffsetToPointer(pcopy, pContext->Offload.ipHeaderOffset), 1216 len, 1217 pcrAnyChecksum/* | pcrFixAnyChecksum*/, 1218 __FUNCTION__); 1219 /* 1220 if (res.xxpStatus == ppresXxpKnown) 1221 { 1222 TCPHeader *ptcp = (TCPHeader *) 1223 RtlOffsetToPointer(pcopy, pContext->Offload.ipHeaderOffset + res.ipHeaderSize); 1224 pse->fullTCPCheckSum = ptcp->tcp_xsum; 1225 } 1226 */ 1227 NdisFreeMemory(pcopy, 0, 0); 1228 } 1229 } 1230 return pse; 1231 } 1232 1233 /********************************************************** 1234 NDIS sends us packets 1235 Queues packets internally and calls the procedure to process the queue 1236 1237 Parameters: 1238 context 1239 IN PPNDIS_PACKET PacketArray Array of packets to send 1240 IN UINT NumberOfPackets number of packets 1241 1242 ***********************************************************/ 1243 VOID NTAPI ParaNdis5_SendPackets(IN NDIS_HANDLE MiniportAdapterContext, 1244 IN PPNDIS_PACKET PacketArray, 1245 IN UINT NumberOfPackets) 1246 { 1247 UINT i; 1248 LIST_ENTRY FailedList, DoneList; 1249 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 1250 InitializeListHead(&FailedList); 1251 InitializeListHead(&DoneList); 1252 DPrintf(3, ("[%s] %d packets", __FUNCTION__, NumberOfPackets)); 1253 ParaNdis_DebugHistory(pContext, hopSend, NULL, 1, NumberOfPackets, 0); 1254 1255 NdisAcquireSpinLock(&pContext->SendLock); 1256 1257 for (i = 0; i < NumberOfPackets; ++i) 1258 { 1259 UINT uPacketLength = 0; 1260 NdisQueryPacketLength(PacketArray[i], &uPacketLength); 1261 NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_SUCCESS); 1262 NdisInterlockedIncrement(&pContext->NetTxPacketsToReturn); 1263 if (!pContext->bSurprizeRemoved && pContext->bConnected && pContext->SendState == srsEnabled && uPacketLength) 1264 { 1265 tSendEntry *pse = PrepareSendEntry(pContext, PacketArray[i], uPacketLength); 1266 if (!pse) 1267 { 1268 NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_FAILURE); 1269 CompletePacket(pContext, PacketArray[i]); 1270 } 1271 else 1272 { 1273 UINT nFragments = 0; 1274 GET_NUMBER_OF_SG_ELEMENTS(PacketArray[i], &nFragments); 1275 ParaNdis_DebugHistory(pContext, hopSendPacketMapped, PacketArray[i], 0, nFragments, 0); 1276 InsertTailList(&pContext->SendQueue, &pse->list); 1277 } 1278 } 1279 else 1280 { 1281 NDIS_STATUS status = NDIS_STATUS_FAILURE; 1282 if (pContext->bSurprizeRemoved) status = NDIS_STATUS_NOT_ACCEPTED; 1283 NDIS_SET_PACKET_STATUS(PacketArray[i], status); 1284 CompletePacket(pContext, PacketArray[i]); 1285 DPrintf(1, ("[%s] packet of %d rejected", __FUNCTION__, uPacketLength)); 1286 } 1287 } 1288 1289 NdisReleaseSpinLock(&pContext->SendLock); 1290 1291 ParaNdis_ProcessTx(pContext, FALSE, FALSE); 1292 } 1293 1294 /********************************************************** 1295 NDIS procedure, not easy to test 1296 NDIS asks us to cancel packets with specified CancelID 1297 1298 Parameters: 1299 context 1300 PVOID CancelId ID to cancel 1301 1302 ***********************************************************/ 1303 VOID NTAPI ParaNdis5_CancelSendPackets(IN NDIS_HANDLE MiniportAdapterContext,IN PVOID CancelId) 1304 { 1305 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 1306 LIST_ENTRY DoneList, KeepList; 1307 UINT n = 0; 1308 tSendEntry *pEntry; 1309 DEBUG_ENTRY(0); 1310 InitializeListHead(&DoneList); 1311 InitializeListHead(&KeepList); 1312 NdisAcquireSpinLock(&pContext->SendLock); 1313 while ( !IsListEmpty(&pContext->SendQueue)) 1314 { 1315 PNDIS_PACKET Packet; 1316 pEntry = (tSendEntry *)RemoveHeadList(&pContext->SendQueue); 1317 Packet = pEntry->packet; 1318 if (NDIS_GET_PACKET_CANCEL_ID(Packet) == CancelId) 1319 { 1320 InsertTailList(&DoneList, &pEntry->list); 1321 ++n; 1322 } 1323 else InsertTailList(&KeepList, &pEntry->list); 1324 } 1325 while ( !IsListEmpty(&KeepList)) 1326 { 1327 pEntry = (tSendEntry *)RemoveHeadList(&KeepList); 1328 InsertTailList(&pContext->SendQueue, &pEntry->list); 1329 } 1330 NdisReleaseSpinLock(&pContext->SendLock); 1331 while (!IsListEmpty(&DoneList)) 1332 { 1333 pEntry = (tSendEntry *)RemoveHeadList(&DoneList); 1334 NDIS_SET_PACKET_STATUS(pEntry->packet, NDIS_STATUS_REQUEST_ABORTED); 1335 CompletePacket(pContext, pEntry->packet); 1336 NdisFreeMemory(pEntry, 0, 0); 1337 } 1338 DEBUG_EXIT_STATUS(0, n); 1339 } 1340 1341 /********************************************************** 1342 Request to pause or resume data transmit 1343 if stopped, all the packets in internal queue are returned 1344 Parameters: 1345 context 1346 BOOLEAN bStop 1/0 - top or resume 1347 ***********************************************************/ 1348 NDIS_STATUS ParaNdis5_StopSend(PARANDIS_ADAPTER *pContext, BOOLEAN bStop, ONPAUSECOMPLETEPROC Callback) 1349 { 1350 NDIS_STATUS status = NDIS_STATUS_SUCCESS; 1351 if (bStop) 1352 { 1353 LIST_ENTRY DoneList; 1354 tSendEntry *pEntry; 1355 DEBUG_ENTRY(0); 1356 ParaNdis_DebugHistory(pContext, hopInternalSendPause, NULL, 1, 0, 0); 1357 InitializeListHead(&DoneList); 1358 NdisAcquireSpinLock(&pContext->SendLock); 1359 if (IsListEmpty(&pContext->TxWaitingList)) 1360 { 1361 pContext->SendState = srsDisabled; 1362 while (!IsListEmpty(&pContext->SendQueue)) 1363 { 1364 pEntry = (tSendEntry *)RemoveHeadList(&pContext->SendQueue); 1365 InsertTailList(&DoneList, &pEntry->list); 1366 } 1367 ParaNdis_DebugHistory(pContext, hopInternalSendPause, NULL, 0, 0, 0); 1368 } 1369 else 1370 { 1371 pContext->SendState = srsPausing; 1372 pContext->SendPauseCompletionProc = Callback; 1373 status = NDIS_STATUS_PENDING; 1374 while (!IsListEmpty(&pContext->SendQueue)) 1375 { 1376 pEntry = (tSendEntry *)RemoveHeadList(&pContext->SendQueue); 1377 pEntry->flags |= SEND_ENTRY_FLAG_READY; 1378 InsertTailList(&pContext->TxWaitingList, &pEntry->list); 1379 } 1380 } 1381 1382 NdisReleaseSpinLock(&pContext->SendLock); 1383 while (!IsListEmpty(&DoneList)) 1384 { 1385 pEntry = (tSendEntry *)RemoveHeadList(&DoneList); 1386 NDIS_SET_PACKET_STATUS(pEntry->packet, NDIS_STATUS_REQUEST_ABORTED); 1387 CompletePacket(pContext, pEntry->packet); 1388 NdisFreeMemory(pEntry, 0, 0); 1389 } 1390 } 1391 else 1392 { 1393 pContext->SendState = srsEnabled; 1394 ParaNdis_DebugHistory(pContext, hopInternalSendResume, NULL, 0, 0, 0); 1395 } 1396 return status; 1397 } 1398 1399 /********************************************************** 1400 Pause or resume receive operation: 1401 Parameters: 1402 context 1403 BOOLEAN bStop 1/0 - pause or resume 1404 ONPAUSECOMPLETEPROC Callback callback to call, if not completed immediately 1405 1406 Return value: 1407 SUCCESS, if there is no RX packets under NDIS management 1408 PENDING, if we need to wait until NDIS returns us packets 1409 ***********************************************************/ 1410 NDIS_STATUS ParaNdis5_StopReceive( 1411 PARANDIS_ADAPTER *pContext, 1412 BOOLEAN bStop, 1413 ONPAUSECOMPLETEPROC Callback 1414 ) 1415 { 1416 NDIS_STATUS status = NDIS_STATUS_SUCCESS; 1417 if (bStop) 1418 { 1419 ParaNdis_DebugHistory(pContext, hopInternalReceivePause, NULL, 1, 0, 0); 1420 NdisAcquireSpinLock(&pContext->ReceiveLock); 1421 if (IsListEmpty(&pContext->NetReceiveBuffersWaiting)) 1422 { 1423 pContext->ReceiveState = srsDisabled; 1424 ParaNdis_DebugHistory(pContext, hopInternalReceivePause, NULL, 0, 0, 0); 1425 } 1426 else 1427 { 1428 pContext->ReceiveState = srsPausing; 1429 pContext->ReceivePauseCompletionProc = Callback; 1430 status = NDIS_STATUS_PENDING; 1431 } 1432 NdisReleaseSpinLock(&pContext->ReceiveLock); 1433 } 1434 else 1435 { 1436 pContext->ReceiveState = srsEnabled; 1437 ParaNdis_DebugHistory(pContext, hopInternalReceiveResume, NULL, 0, 0, 0); 1438 } 1439 return status; 1440 } 1441 1442 /************************************************************* 1443 Required NDIS procedure, spawns regular (Common) DPC processing 1444 *************************************************************/ 1445 VOID NTAPI ParaNdis5_HandleDPC(IN NDIS_HANDLE MiniportAdapterContext) 1446 { 1447 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 1448 ULONG requiresProcessing; 1449 BOOLEAN unused; 1450 DEBUG_ENTRY(7); 1451 // we do not need the timer, as DPC will do all the job 1452 // this is not a problem if the timer procedure is already running, 1453 // we need to do our job anyway 1454 NdisCancelTimer(&pContext->DPCPostProcessTimer, &unused); 1455 requiresProcessing = ParaNdis_DPCWorkBody(pContext, PARANDIS_UNLIMITED_PACKETS_TO_INDICATE); 1456 if (requiresProcessing) 1457 { 1458 // we need to request additional DPC 1459 InterlockedOr(&pContext->InterruptStatus, requiresProcessing); 1460 NdisSetTimer(&pContext->DPCPostProcessTimer, 10); 1461 } 1462 } 1463 1464 BOOLEAN ParaNdis_SynchronizeWithInterrupt( 1465 PARANDIS_ADAPTER *pContext, 1466 ULONG messageId, 1467 tSynchronizedProcedure procedure, 1468 PVOID parameter) 1469 { 1470 tSynchronizedContext SyncContext; 1471 SyncContext.pContext = pContext; 1472 SyncContext.Parameter = parameter; 1473 return NdisMSynchronizeWithInterrupt(&pContext->Interrupt, procedure, &SyncContext); 1474 } 1475