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 ***********************************************************/
ParaNdis_AllocateMemory(PARANDIS_ADAPTER * pContext,ULONG ulRequiredSize)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 ***********************************************************/
ParaNdis_OpenNICConfiguration(PARANDIS_ADAPTER * pContext)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
ParaNdis_RestoreDeviceConfigurationAfterReset(PARANDIS_ADAPTER * pContext)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 ***********************************************************/
ParaNdis_IndicateConnect(PARANDIS_ADAPTER * pContext,BOOLEAN bConnected,BOOLEAN bForce)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
ParaNdis_SetPowerState(PARANDIS_ADAPTER * pContext,NDIS_DEVICE_POWER_STATE newState)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 ***********************************************************/
OnConnectTimer(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)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 ***********************************************************/
ParaNdis_InitialAllocatePhysicalMemory(PARANDIS_ADAPTER * pContext,tCompletePhysicalAddress * pAddresses)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 ***********************************************************/
OnDPCPostProcessTimer(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)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 ***********************************************************/
ParaNdis_FreePhysicalMemory(PARANDIS_ADAPTER * pContext,tCompletePhysicalAddress * pAddresses)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
DebugParseOffloadBits()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 ***********************************************************/
ParaNdis_FinishSpecificInitialization(PARANDIS_ADAPTER * pContext)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 ***********************************************************/
ParaNdis_FinalizeCleanup(PARANDIS_ADAPTER * pContext)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
MaxNdisBufferDataSize(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBufferDesc)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 ***********************************************************/
ParaNdis_BindBufferToPacket(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBufferDesc)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 ***********************************************************/
ParaNdis_UnbindBufferFromPacket(PARANDIS_ADAPTER * pContext,pIONetDescriptor pBufferDesc)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 ***********************************************************/
ParaNdis_IndicateReceivedPacket(PARANDIS_ADAPTER * pContext,PVOID dataBuffer,PULONG pLength,BOOLEAN bPrepareOnly,pIONetDescriptor pBuffersDesc)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
ParaNdis_IndicateReceivedBatch(PARANDIS_ADAPTER * pContext,tPacketIndicationType * pBatch,ULONG nofPackets)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
GET_NUMBER_OF_SG_ELEMENTS(PNDIS_PACKET Packet,UINT * pNum)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 ***********************************************************/
CompletePacket(PARANDIS_ADAPTER * pContext,PNDIS_PACKET Packet)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 ***********************************************************/
ParaNdis_PacketCopier(PNDIS_PACKET Packet,PVOID dest,ULONG maxSize,PVOID refValue,BOOLEAN bPreview)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 ***********************************************************/
ParaNdis_OnTransmitBufferReleased(PARANDIS_ADAPTER * pContext,IONetDescriptor * pDesc)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
CalculateTotalOffloadSize(ULONG packetSize,ULONG mss,ULONG ipheaderOffset,ULONG maxPossiblePacketSize,tTcpIpPacketParsingResult packetReview)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 ***********************************************************/
ParaNdis_PacketMapper(PARANDIS_ADAPTER * pContext,PNDIS_PACKET packet,PVOID ReferenceValue,struct VirtIOBufferDescriptor * buffers,pIONetDescriptor pDesc,tMapperResult * pMapperResult)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
InitializeTransferParameters(tTxOperationParameters * pParams,tSendEntry * pEntry)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
ParaNdis_ProcessTx(PARANDIS_ADAPTER * pContext,BOOLEAN IsDpc,BOOLEAN IsInterrupt)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 ***********************************************************/
ParaNdis5_ReturnPacket(IN NDIS_HANDLE MiniportAdapterContext,IN PNDIS_PACKET Packet)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
PrepareSendEntry(PARANDIS_ADAPTER * pContext,PNDIS_PACKET Packet,ULONG len)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 ***********************************************************/
ParaNdis5_SendPackets(IN NDIS_HANDLE MiniportAdapterContext,IN PPNDIS_PACKET PacketArray,IN UINT NumberOfPackets)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 ***********************************************************/
ParaNdis5_CancelSendPackets(IN NDIS_HANDLE MiniportAdapterContext,IN PVOID CancelId)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 ***********************************************************/
ParaNdis5_StopSend(PARANDIS_ADAPTER * pContext,BOOLEAN bStop,ONPAUSECOMPLETEPROC Callback)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 ***********************************************************/
ParaNdis5_StopReceive(PARANDIS_ADAPTER * pContext,BOOLEAN bStop,ONPAUSECOMPLETEPROC Callback)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 *************************************************************/
ParaNdis5_HandleDPC(IN NDIS_HANDLE MiniportAdapterContext)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
ParaNdis_SynchronizeWithInterrupt(PARANDIS_ADAPTER * pContext,ULONG messageId,tSynchronizedProcedure procedure,PVOID parameter)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