Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1034 lines
27 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. Offload.c
  5. Abstract:
  6. This file contains all the functions needed by TCP/IP checksum and segmentation
  7. of Large TCP packets task offloading. Actually thses functions should be
  8. implemented by hardware, and the purpose of this file is just to demonstrate
  9. how to use OID_TCP_TASK_OFFLOAD to enable/disable task offload capabilities.
  10. Revision History
  11. Who When What
  12. ------ --------- ----------
  13. 02-19-2001 Create
  14. Notes:
  15. --*/
  16. #include "precomp.h"
  17. #ifdef OFFLOAD
  18. #define PROTOCOL_TCP 6
  19. //
  20. // This miniport uses shared memory to handle offload tasks, so it tries to allocate
  21. // shared memory of 64K, 32K, 16K. First it tries to allocate 64K, if fails, then
  22. // it tries 32K and so on. If successed, than keeps the size in adapter, which is used
  23. // to decide the maximum offload size in large send. If all the tries fail, then this
  24. // miniport cann't support any offload task.
  25. //
  26. ULONG LargeSendSharedMemArray[LARGE_SEND_MEM_SIZE_OPTION] = {64*1024, 32*1024, 16*1024};
  27. //
  28. // if x is aabb(where aa, bb are hex bytes), we want net_short (x) to be bbaa.
  29. //
  30. USHORT net_short(
  31. ULONG NaturalData
  32. )
  33. {
  34. USHORT ShortData = (USHORT)NaturalData;
  35. return (ShortData << 8) | (ShortData >> 8);
  36. }
  37. //
  38. // if x is aabbccdd (where aa, bb, cc, dd are hex bytes)
  39. // we want net_long(x) to be ddccbbaa. A small and fast way to do this is
  40. // to first byteswap it to get bbaaddcc and then swap high and low words.
  41. //
  42. ULONG net_long(
  43. ULONG NaturalData
  44. )
  45. {
  46. ULONG ByteSwapped;
  47. ByteSwapped = ((NaturalData & 0x00ff00ff) << 8) |
  48. ((NaturalData & 0xff00ff00) >> 8);
  49. return (ByteSwapped << 16) | (ByteSwapped >> 16);
  50. }
  51. //
  52. // calculate the checksum for pseudo-header
  53. //
  54. #define PHXSUM(s,d,p,l) (UINT)( (UINT)*(USHORT *)&(s) + \
  55. (UINT)*(USHORT *)((char *)&(s) + sizeof(USHORT)) + \
  56. (UINT)*(USHORT *)&(d) + \
  57. (UINT)*(USHORT *)((char *)&(d) + sizeof(USHORT)) + \
  58. (UINT)((USHORT)net_short((p))) + \
  59. (UINT)((USHORT)net_short((USHORT)(l))) )
  60. #define IP_HEADER_LENGTH(pIpHdr) \
  61. ( (ULONG)((pIpHdr->iph_verlen & 0x0F) << 2) )
  62. #define TCP_HEADER_LENGTH(pTcpHdr) \
  63. ( (USHORT)(((*((PUCHAR)(&(pTcpHdr->tcp_flags))) & 0xF0) >> 4) << 2) )
  64. /*++
  65. Routine Description:
  66. Copy data in a packet to the specified location
  67. Arguments:
  68. BytesToCopy The number of bytes need to copy
  69. CurrentBuffer The buffer to start to copy
  70. StartVa The start address to copy the data to
  71. Offset The start offset in the buffer to copy the data
  72. HeadersLength The length of the headers which has already been copied.
  73. Return Value:
  74. The number of bytes actually copied
  75. --*/
  76. ULONG MpCopyData(
  77. ULONG BytesToCopy,
  78. PNDIS_BUFFER *CurrentBuffer,
  79. PVOID StartVa,
  80. PULONG Offset,
  81. ULONG HeadersLength
  82. )
  83. {
  84. ULONG CurrLength;
  85. PUCHAR pSrc;
  86. PUCHAR pDest;
  87. ULONG BytesCopied = 0;
  88. ULONG CopyLength;
  89. DBGPRINT(MP_TRACE, ("--> MpCopyData\n"));
  90. pDest = StartVa;
  91. while (*CurrentBuffer && BytesToCopy != 0)
  92. {
  93. #ifdef NDIS51_MINIPORT
  94. NdisQueryBufferSafe(
  95. *CurrentBuffer,
  96. &pSrc,
  97. &CurrLength,
  98. NormalPagePriority);
  99. if (pSrc == NULL)
  100. {
  101. BytesCopied = 0;
  102. break;
  103. }
  104. #else
  105. NdisQueryBuffer( *CurrentBuffer, &pSrc, &CurrLength);
  106. #endif
  107. //
  108. // Current buffer length is greater than the offset to the buffer
  109. //
  110. if (CurrLength > *Offset)
  111. {
  112. pSrc += *Offset;
  113. CurrLength -= *Offset;
  114. CopyLength = CurrLength > BytesToCopy ? BytesToCopy : CurrLength;
  115. NdisMoveMemory(pDest, pSrc, CopyLength);
  116. BytesCopied += CopyLength;
  117. if (CurrLength > BytesToCopy)
  118. {
  119. *Offset += BytesToCopy;
  120. break;
  121. }
  122. BytesToCopy -= CopyLength;
  123. pDest += CopyLength;
  124. *Offset = 0;
  125. }
  126. else
  127. {
  128. *Offset -= CurrLength;
  129. }
  130. NdisGetNextBuffer( *CurrentBuffer, CurrentBuffer);
  131. }
  132. ASSERT(BytesCopied + HeadersLength <= NIC_MAX_PACKET_SIZE);
  133. //
  134. // Zero out the padding bytes if necessary
  135. //
  136. if (BytesCopied + HeadersLength < NIC_MIN_PACKET_SIZE)
  137. {
  138. NdisZeroMemory(pDest, NIC_MIN_PACKET_SIZE - (BytesCopied + HeadersLength));
  139. }
  140. DBGPRINT(MP_TRACE, ("<-- MpCopyData\n"));
  141. return BytesCopied;
  142. }
  143. /*++
  144. Routine Description:
  145. Dump packet information for debug purpose
  146. Arguments:
  147. pPkt Pointer to the packet
  148. Return Value:
  149. None
  150. --*/
  151. VOID e100DumpPkt (
  152. IN PNDIS_PACKET Packet
  153. )
  154. {
  155. PNDIS_BUFFER pPrevBuffer;
  156. PNDIS_BUFFER pBuffer;
  157. do
  158. {
  159. //
  160. // Get first buffer of the packet
  161. //
  162. pBuffer = Packet->Private.Head;
  163. pPrevBuffer = NULL;
  164. //
  165. // Scan the buffer chain
  166. //
  167. while (pBuffer != NULL)
  168. {
  169. PVOID pVa = NULL;
  170. ULONG BufLen = 0;
  171. BufLen = NdisBufferLength (pBuffer);
  172. pVa = NdisBufferVirtualAddress(pBuffer);
  173. pPrevBuffer = pBuffer;
  174. pBuffer = pBuffer->Next;
  175. if (pVa == NULL)
  176. {
  177. continue;
  178. }
  179. DBGPRINT(MP_WARN, ("Mdl %p, Va %p. Len %x\n", pPrevBuffer, pVa, BufLen));
  180. Dump( (CHAR* )pVa, BufLen, 0, 1 );
  181. }
  182. } while (FALSE);
  183. }
  184. /*++
  185. Routine Description:
  186. Calculate the IP checksum
  187. Arguments:
  188. Packet Pointer to the packet
  189. IpHdrOffset Offset of IP header from the beginning of the packet
  190. Return Value:
  191. None
  192. --*/
  193. VOID CalculateIpChecksum(
  194. PUCHAR StartVa,
  195. ULONG IpHdrOffset
  196. )
  197. {
  198. IPHeader *pIpHdr;
  199. ULONG IpHdrLen;
  200. ULONG TempXsum = 0;
  201. pIpHdr = (IPHeader *)(StartVa + IpHdrOffset);
  202. IpHdrLen = IP_HEADER_LENGTH(pIpHdr);
  203. XSUM(TempXsum, StartVa, IpHdrLen, IpHdrOffset);
  204. pIpHdr->iph_xsum = ~(USHORT)TempXsum;
  205. }
  206. /*++
  207. Routine Description:
  208. Calculate the UDP checksum
  209. Arguments:
  210. Packet Pointer to the packet
  211. IpHdrOffset Offset of IP header from the beginning of the packet
  212. Return Value:
  213. None
  214. --*/
  215. VOID CalculateUdpChecksum(
  216. PNDIS_PACKET pPacket,
  217. ULONG IpHdrOffset
  218. )
  219. {
  220. DBGPRINT(MP_WARN, ("UdpChecksum is not handled\n"));
  221. }
  222. /*++
  223. Routine Description:
  224. Calculate the TCP checksum
  225. Arguments:
  226. Packet Pointer to the packet
  227. IpHdrOffset Offset of IP header from the beginning of the packet
  228. Return Value:
  229. None
  230. --*/
  231. VOID CalculateTcpChecksum(
  232. PVOID StartVa,
  233. ULONG PacketLength,
  234. ULONG IpHdrOffset
  235. )
  236. {
  237. ULONG Offset;
  238. IPHeader *pIpHdr;
  239. ULONG IpHdrLength;
  240. TCPHeader *pTcpHdr;
  241. USHORT PseudoXsum;
  242. ULONG TmpXsum;
  243. DBGPRINT(MP_TRACE, ("===> CalculateTcpChecksum\n"));
  244. //
  245. // Find IP header and get IP header length in byte
  246. // MDL won't split headers
  247. //
  248. Offset = IpHdrOffset;
  249. pIpHdr = (IPHeader *) ((PUCHAR)StartVa + Offset);
  250. IpHdrLength = IP_HEADER_LENGTH(pIpHdr);
  251. //
  252. // If that is not tcp protocol, we can not do anything.
  253. // So just return to the caller
  254. //
  255. if (((pIpHdr->iph_verlen & 0xF0) >> 4) != 4 && pIpHdr->iph_protocol != PROTOCOL_TCP)
  256. {
  257. return;
  258. }
  259. //
  260. // Locate the TCP header
  261. //
  262. Offset += IpHdrLength;
  263. pTcpHdr = (TCPHeader *) ((PUCHAR)StartVa + Offset);
  264. //
  265. // Calculate the checksum for the tcp header and payload
  266. //
  267. PseudoXsum = pTcpHdr->tcp_xsum;
  268. pTcpHdr->tcp_xsum = 0;
  269. TmpXsum = PseudoXsum;
  270. XSUM(TmpXsum, StartVa, PacketLength - Offset, Offset);
  271. //
  272. // Now we got the checksum, need to put the checksum back to MDL
  273. //
  274. pTcpHdr->tcp_xsum = (USHORT)(~TmpXsum);
  275. DBGPRINT(MP_TRACE, ("<=== CalculateTcpChecksum\n"));
  276. }
  277. /*++
  278. Routine Description:
  279. Do the checksum offloading
  280. Arguments:
  281. Packet Pointer to the packet
  282. IpHdrOffset Offset of IP header from the beginning of the packet
  283. Return Value:
  284. None
  285. --*/
  286. VOID CalculateChecksum(
  287. PVOID StartVa,
  288. ULONG PacketLength,
  289. PNDIS_PACKET Packet,
  290. ULONG IpHdrOffset
  291. )
  292. {
  293. ULONG ChecksumPktInfo;
  294. PNDIS_TCP_IP_CHECKSUM_PACKET_INFO pChecksumPktInfo;
  295. //
  296. // Check for protocol
  297. //
  298. if (NDIS_PROTOCOL_ID_TCP_IP != NDIS_GET_PACKET_PROTOCOL_TYPE(Packet))
  299. {
  300. DBGPRINT(MP_TRACE, ("Packet's protocol is wrong.\n"));
  301. return;
  302. }
  303. //
  304. // Query per packet information
  305. //
  306. ChecksumPktInfo = PtrToUlong(
  307. NDIS_PER_PACKET_INFO_FROM_PACKET( Packet,
  308. TcpIpChecksumPacketInfo));
  309. // DBGPRINT(MP_WARN, ("Checksum info: %lu\n", ChecksumPktInfo));
  310. pChecksumPktInfo = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO) & ChecksumPktInfo;
  311. //
  312. // Check per packet information
  313. //
  314. if (pChecksumPktInfo->Transmit.NdisPacketChecksumV4 == 0)
  315. {
  316. DBGPRINT(MP_TRACE, ("NdisPacketChecksumV4 is not set.\n"));
  317. return;
  318. }
  319. //
  320. // do tcp checksum
  321. //
  322. if (pChecksumPktInfo->Transmit.NdisPacketTcpChecksum)
  323. {
  324. CalculateTcpChecksum(StartVa, PacketLength, IpHdrOffset);
  325. }
  326. //
  327. // do udp checksum
  328. //
  329. if (pChecksumPktInfo->Transmit.NdisPacketUdpChecksum)
  330. {
  331. CalculateUdpChecksum(Packet, IpHdrOffset);
  332. }
  333. //
  334. // do ip checksum
  335. //
  336. if (pChecksumPktInfo->Transmit.NdisPacketIpChecksum)
  337. {
  338. CalculateIpChecksum(StartVa, IpHdrOffset);
  339. }
  340. }
  341. /*++
  342. Routine Description:
  343. MiniportSendPackets handler
  344. Arguments:
  345. MiniportAdapterContext Pointer to our adapter
  346. PacketArray Set of packets to send
  347. NumOfPackets Self-explanatory
  348. Return Value:
  349. None
  350. --*/
  351. VOID MPOffloadSendPackets(
  352. IN NDIS_HANDLE MiniportAdapterContext,
  353. IN PPNDIS_PACKET PacketArray,
  354. IN UINT NumOfPackets
  355. )
  356. {
  357. PMP_ADAPTER Adapter;
  358. NDIS_STATUS Status;
  359. UINT PacketCount;
  360. ULONG IpHdrOffset;
  361. DBGPRINT(MP_TRACE, ("====> MPOffloadSendPackets\n"));
  362. Adapter = (PMP_ADAPTER)MiniportAdapterContext;
  363. NdisAcquireSpinLock(&Adapter->SendLock);
  364. //
  365. // Is this adapter ready for sending?
  366. //
  367. if (MP_IS_NOT_READY(Adapter))
  368. {
  369. //
  370. // There is link
  371. //
  372. if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION))
  373. {
  374. for (PacketCount = 0; PacketCount < NumOfPackets; PacketCount++)
  375. {
  376. InsertTailQueue(&Adapter->SendWaitQueue,
  377. MP_GET_PACKET_MR( PacketArray[PacketCount] )
  378. );
  379. Adapter->nWaitSend++;
  380. DBGPRINT(MP_WARN, ("MpOffloadSendPackets: link detection - queue packet "PTR_FORMAT"\n", PacketArray[PacketCount]));
  381. }
  382. NdisReleaseSpinLock(&Adapter->SendLock);
  383. return;
  384. }
  385. //
  386. // Adapter is not ready and there is not link
  387. //
  388. Status = MP_GET_STATUS_FROM_FLAGS(Adapter);
  389. NdisReleaseSpinLock(&Adapter->SendLock);
  390. for (PacketCount = 0; PacketCount < NumOfPackets; PacketCount++)
  391. {
  392. NdisMSendComplete(
  393. MP_GET_ADAPTER_HANDLE(Adapter),
  394. PacketArray[PacketCount],
  395. Status);
  396. }
  397. return;
  398. }
  399. //
  400. // Adapter is ready, send these packets
  401. //
  402. for (PacketCount = 0; PacketCount < NumOfPackets; PacketCount++)
  403. {
  404. //
  405. // queue is not empty or tcb is not available
  406. //
  407. if (!IsQueueEmpty(&Adapter->SendWaitQueue) ||
  408. !MP_TCB_RESOURCES_AVAIABLE(Adapter) ||
  409. MP_TEST_FLAG(Adapter, fMP_SHARED_MEM_IN_USE))
  410. {
  411. InsertTailQueue(&Adapter->SendWaitQueue,
  412. MP_GET_PACKET_MR( PacketArray[PacketCount] )
  413. );
  414. Adapter->nWaitSend++;
  415. }
  416. else
  417. {
  418. MpOffloadSendPacket(Adapter, PacketArray[PacketCount], FALSE);
  419. }
  420. }
  421. NdisReleaseSpinLock(&Adapter->SendLock);
  422. DBGPRINT(MP_TRACE, ("<==== MPOffloadSendPackets\n"));
  423. return;
  424. }
  425. /*++
  426. Routine Description:
  427. Do the work to send a packet
  428. Assumption: Send spinlock has been acquired and shared mem is available
  429. Arguments:
  430. Adapter Pointer to our adapter
  431. Packet The packet
  432. bFromQueue TRUE if it's taken from the send wait queue
  433. Return Value:
  434. NDIS_STATUS_SUCCESS
  435. NDIS_STATUS_PENDING Put into the send wait queue
  436. NDIS_STATUS_HARD_ERRORS
  437. --*/
  438. NDIS_STATUS MpOffloadSendPacket(
  439. IN PMP_ADAPTER Adapter,
  440. IN PNDIS_PACKET Packet,
  441. IN BOOLEAN bFromQueue
  442. )
  443. {
  444. NDIS_STATUS Status = NDIS_STATUS_PENDING;
  445. PMP_TCB pMpTcb = NULL;
  446. ULONG BytesCopied;
  447. ULONG NumOfPackets;
  448. // Mimiced frag list if map registers are used, on the local stack as it's not so big
  449. MP_FRAG_LIST FragList;
  450. // Pointer to either the scatter gather or the local mimiced frag list
  451. PMP_FRAG_LIST pFragList;
  452. NDIS_PHYSICAL_ADDRESS SendPa;
  453. ULONG BytesToCopy;
  454. ULONG Offset;
  455. PNDIS_PACKET_EXTENSION PktExt;
  456. ULONG mss;
  457. PNDIS_BUFFER NdisBuffer;
  458. ULONG PacketLength;
  459. PVOID CopyStartVa;
  460. ULONG IpHdrOffset;
  461. PUCHAR StartVa;
  462. PNDIS_BUFFER FirstBuffer;
  463. DBGPRINT(MP_TRACE, ("--> MpOffloadSendPacket, Pkt= "PTR_FORMAT"\n", Packet));
  464. //
  465. //Check is shared memory available, just double check
  466. //
  467. if (MP_TEST_FLAG(Adapter, fMP_SHARED_MEM_IN_USE))
  468. {
  469. DBGPRINT(MP_WARN, ("Shared mem is in use.\n"));
  470. if (bFromQueue)
  471. {
  472. InsertHeadQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(Packet));
  473. }
  474. else
  475. {
  476. InsertTailQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(Packet));
  477. }
  478. DBGPRINT(MP_TRACE, ("<-- MpOffloadSendPacket\n"));
  479. return Status;
  480. }
  481. MP_SET_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
  482. //
  483. // Get maximum segment size
  484. //
  485. PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);
  486. mss = PtrToUlong(PktExt->NdisPacketInfo[TcpLargeSendPacketInfo]);
  487. //
  488. // Copy NIC_MAX_PACKET_SIZE bytes of data from NDIS buffer
  489. // to the shared memory
  490. //
  491. NdisQueryPacket( Packet, NULL, NULL, &FirstBuffer, &PacketLength );
  492. Offset = 0;
  493. NdisBuffer = FirstBuffer;
  494. BytesToCopy = NIC_MAX_PACKET_SIZE;
  495. CopyStartVa = Adapter->OffloadSharedMem.StartVa;
  496. BytesCopied = MpCopyData(BytesToCopy, &NdisBuffer, CopyStartVa, &Offset, 0);
  497. #ifdef NDIS51_MINIPORT
  498. //
  499. // MpCopyPacket may return 0 if system resources are low or exhausted
  500. //
  501. if (BytesCopied == 0)
  502. {
  503. DBGPRINT(MP_ERROR, ("Calling NdisMSendComplete with NDIS_STATUS_RESOURCES, Pkt= "PTR_FORMAT"\n", Packet));
  504. NdisReleaseSpinLock(&Adapter->SendLock);
  505. NdisMSendComplete(
  506. MP_GET_ADAPTER_HANDLE(Adapter),
  507. Packet,
  508. NDIS_STATUS_RESOURCES);
  509. NdisAcquireSpinLock(&Adapter->SendLock);
  510. MP_CLEAR_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
  511. return NDIS_STATUS_RESOURCES;
  512. }
  513. #endif
  514. StartVa = CopyStartVa;
  515. SendPa = Adapter->OffloadSharedMem.PhyAddr;
  516. IpHdrOffset = Adapter->EncapsulationFormat.EncapsulationHeaderSize;
  517. //
  518. // Check if large send capability is on and this is a large packet
  519. //
  520. if (Adapter->NicTaskOffload.LargeSendOffload && mss > 0)
  521. {
  522. ULONG IpHeaderLen;
  523. ULONG TcpHdrOffset;
  524. ULONG HeadersLen;
  525. IPHeader * IpHdr;
  526. TCPHeader * TcpHdr;
  527. USHORT TcpHeaderLen;
  528. ULONG IpSegmentLen;
  529. ULONG TcpDataLen;
  530. ULONG LastPacketDataLen;
  531. int SeqNum;
  532. BOOLEAN IsFinSet = FALSE;
  533. BOOLEAN IsPushSet = FALSE;
  534. BOOLEAN IsFirstSlot = TRUE;
  535. ULONG TmpXsum;
  536. ULONG BytesSent = 0;
  537. ULONG TmpPxsum;
  538. IpHdr = (IPHeader *)((PUCHAR)CopyStartVa + IpHdrOffset);
  539. IpHeaderLen = IP_HEADER_LENGTH(IpHdr);
  540. //
  541. // The packet must be a TCP packet
  542. //
  543. ASSERT(IpHdr->iph_protocol == PROTOCOL_TCP);
  544. TcpHdrOffset = IpHdrOffset + IpHeaderLen;
  545. TcpHdr = (TCPHeader *)((PUCHAR)CopyStartVa + TcpHdrOffset);
  546. TcpHeaderLen = TCP_HEADER_LENGTH(TcpHdr);
  547. HeadersLen = TcpHdrOffset + TcpHeaderLen;
  548. //
  549. // This length include IP, TCP headers and TCP data
  550. //
  551. IpSegmentLen = net_short(IpHdr->iph_length);
  552. //
  553. // get the pseudo-header 1's complement sum
  554. //
  555. TmpPxsum = TcpHdr->tcp_xsum;
  556. ASSERT(IpSegmentLen == PacketLength - IpHdrOffset);
  557. IsFinSet = (BOOLEAN)(TcpHdr->tcp_flags & TCP_FLAG_FIN);
  558. IsPushSet = (BOOLEAN)(TcpHdr->tcp_flags & TCP_FLAG_PUSH);
  559. SeqNum = net_long(TcpHdr->tcp_seq);
  560. TcpDataLen = IpSegmentLen - TcpHeaderLen - IpHeaderLen;
  561. ASSERT(TcpDataLen <= Adapter->LargeSendInfo.MaxOffLoadSize)
  562. NumOfPackets = TcpDataLen / mss + 1;
  563. ASSERT (NumOfPackets >= Adapter->LargeSendInfo.MinSegmentCount);
  564. LastPacketDataLen = TcpDataLen % mss;
  565. NdisBuffer = FirstBuffer;
  566. BytesSent = 0;
  567. //
  568. // The next copy start with offset of (mss+HeadersLen) corresponding to first buf
  569. //
  570. BytesCopied = (BytesCopied >= mss + HeadersLen)? (mss + HeadersLen):BytesCopied;
  571. Offset = BytesCopied;
  572. //
  573. // Send out all the packets from the large TCP packet
  574. //
  575. while (NumOfPackets--)
  576. {
  577. TmpXsum = 0;
  578. //
  579. // Is the first packet?
  580. //
  581. if (IsFirstSlot)
  582. {
  583. if (NumOfPackets == 0)
  584. {
  585. PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(BytesCopied);
  586. }
  587. else
  588. {
  589. if (IsFinSet)
  590. {
  591. TcpHdr->tcp_flags &= ~TCP_FLAG_FIN;
  592. }
  593. if (IsPushSet)
  594. {
  595. TcpHdr->tcp_flags &= ~TCP_FLAG_PUSH;
  596. }
  597. }
  598. BytesCopied -= HeadersLen;
  599. IsFirstSlot = FALSE;
  600. }
  601. //
  602. // Not the first packet
  603. //
  604. else
  605. {
  606. //
  607. // copy headers
  608. //
  609. NdisMoveMemory (StartVa, CopyStartVa, HeadersLen);
  610. IpHdr = (IPHeader *)((PUCHAR)StartVa + IpHdrOffset);
  611. TcpHdr = (TCPHeader *) ((PUCHAR)StartVa + TcpHdrOffset);
  612. //
  613. // Last packet
  614. //
  615. if (NumOfPackets == 0)
  616. {
  617. BytesToCopy = LastPacketDataLen;
  618. PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] =
  619. UlongToPtr(BytesSent + LastPacketDataLen);
  620. }
  621. else
  622. {
  623. BytesToCopy = mss;
  624. // clear flag
  625. if (IsFinSet)
  626. {
  627. TcpHdr->tcp_flags &= ~TCP_FLAG_FIN;
  628. }
  629. if (IsPushSet)
  630. {
  631. TcpHdr->tcp_flags &= ~TCP_FLAG_PUSH;
  632. }
  633. }
  634. BytesCopied = MpCopyData(
  635. BytesToCopy,
  636. &NdisBuffer,
  637. StartVa + HeadersLen,
  638. &Offset,
  639. HeadersLen);
  640. #ifdef NDIS51_MINIPORT
  641. //
  642. // MpCopyData may return 0 if system resources are low or exhausted
  643. //
  644. if (BytesCopied == 0)
  645. {
  646. PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(BytesSent);
  647. DBGPRINT(MP_WARN, ("Calling NdisMSendComplete with NDIS_STATUS_SUCCESS(Part of the data is sent), Pkt= "PTR_FORMAT"\n", Packet));
  648. NdisReleaseSpinLock(&Adapter->SendLock);
  649. NdisMSendComplete(
  650. MP_GET_ADAPTER_HANDLE(Adapter),
  651. Packet,
  652. NDIS_STATUS_SUCCESS);
  653. NdisAcquireSpinLock(&Adapter->SendLock);
  654. return NDIS_STATUS_RESOURCES;
  655. }
  656. #endif
  657. }
  658. IpHdr->iph_length = net_short(TcpHeaderLen + IpHeaderLen + BytesCopied);
  659. TcpHdr->tcp_seq = net_long(SeqNum);
  660. SeqNum += BytesCopied;
  661. //
  662. // calculate ip checksum and tcp checksum
  663. //
  664. IpHdr->iph_xsum = 0;
  665. XSUM(TmpXsum, StartVa, IpHeaderLen, IpHdrOffset);
  666. IpHdr->iph_xsum = ~(USHORT)(TmpXsum);
  667. TmpXsum = TmpPxsum + net_short((USHORT)(BytesCopied + TcpHeaderLen));
  668. TcpHdr->tcp_xsum = 0;
  669. XSUM(TmpXsum, StartVa, BytesCopied + TcpHeaderLen, TcpHdrOffset);
  670. TcpHdr->tcp_xsum = ~(USHORT)(TmpXsum);
  671. BytesSent += BytesCopied;
  672. BytesCopied += HeadersLen;
  673. //
  674. // get TCB for the slot
  675. //
  676. pMpTcb = Adapter->CurrSendTail;
  677. ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
  678. //
  679. // Set up the frag list, only one fragment after it's coalesced
  680. //
  681. pFragList = &FragList;
  682. pFragList->NumberOfElements = 1;
  683. pFragList->Elements[0].Address = SendPa;
  684. pFragList->Elements[0].Length = (BytesCopied >= NIC_MIN_PACKET_SIZE) ?
  685. BytesCopied : NIC_MIN_PACKET_SIZE;
  686. pMpTcb->Packet = NULL;
  687. MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);
  688. //
  689. // Call the NIC specific send handler, it only needs to deal with the frag list
  690. //
  691. Status = NICSendPacket(Adapter, pMpTcb, pFragList);
  692. Adapter->nBusySend++;
  693. NdisInterlockedIncrement(&Adapter->SharedMemRefCount);
  694. //
  695. // Update the CopyVa and SendPa
  696. //
  697. SendPa.QuadPart += BytesCopied;
  698. StartVa += BytesCopied;
  699. Adapter->CurrSendTail = Adapter->CurrSendTail->Next;
  700. //
  701. // out of resouces, which will send complete part of the packet
  702. //
  703. if (Adapter->nBusySend >= Adapter->NumTcb)
  704. {
  705. PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(BytesSent);
  706. break;
  707. }
  708. } // while
  709. }
  710. //
  711. // This is not a large packet or large send capability is not on
  712. //
  713. else
  714. {
  715. //
  716. // get TCB for the slot
  717. //
  718. pMpTcb = Adapter->CurrSendTail;
  719. ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
  720. //
  721. // Set up the frag list, only one fragment after it's coalesced
  722. //
  723. pFragList = &FragList;
  724. pFragList->NumberOfElements = 1;
  725. pFragList->Elements[0].Address = SendPa;
  726. pFragList->Elements[0].Length = (BytesCopied >= NIC_MIN_PACKET_SIZE) ?
  727. BytesCopied : NIC_MIN_PACKET_SIZE;
  728. pMpTcb->Packet = NULL;
  729. if (Adapter->NicChecksumOffload.DoXmitTcpChecksum
  730. && Adapter->NicTaskOffload.ChecksumOffload)
  731. {
  732. CalculateChecksum(CopyStartVa,
  733. BytesCopied,
  734. Packet,
  735. Adapter->EncapsulationFormat.EncapsulationHeaderSize);
  736. }
  737. MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);
  738. //
  739. // Call the NIC specific send handler, it only needs to deal with the frag list
  740. //
  741. Status = NICSendPacket(Adapter, pMpTcb, pFragList);
  742. Adapter->nBusySend++;
  743. NdisInterlockedIncrement(&Adapter->SharedMemRefCount);
  744. ASSERT(Adapter->nBusySend <= Adapter->NumTcb);
  745. Adapter->CurrSendTail = Adapter->CurrSendTail->Next;
  746. }
  747. NdisReleaseSpinLock(&Adapter->SendLock);
  748. DBGPRINT(MP_TRACE, ("Calling NdisMSendComplete, Pkt= "PTR_FORMAT"\n", Packet));
  749. NdisMSendComplete( MP_GET_ADAPTER_HANDLE(Adapter), Packet, Status);
  750. NdisAcquireSpinLock(&Adapter->SendLock);
  751. DBGPRINT(MP_TRACE, ("<-- MpOffloadSendPacket\n"));
  752. return Status;
  753. }
  754. /*++
  755. Routine Description:
  756. Recycle a MP_TCB and complete the packet if necessary
  757. Assumption: Send spinlock has been acquired
  758. Arguments:
  759. Adapter Pointer to our adapter
  760. pMpTcb Pointer to MP_TCB
  761. Return Value:
  762. None
  763. --*/
  764. VOID MP_OFFLOAD_FREE_SEND_PACKET(
  765. IN PMP_ADAPTER Adapter,
  766. IN PMP_TCB pMpTcb
  767. )
  768. {
  769. PNDIS_BUFFER CurrBuffer;
  770. ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
  771. pMpTcb->Packet = NULL;
  772. pMpTcb->Count = 0;
  773. MP_CLEAR_FLAGS(pMpTcb);
  774. Adapter->CurrSendHead = Adapter->CurrSendHead->Next;
  775. Adapter->nBusySend--;
  776. NdisInterlockedDecrement(&Adapter->SharedMemRefCount);
  777. if (Adapter->SharedMemRefCount == 0)
  778. {
  779. MP_CLEAR_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
  780. }
  781. ASSERT(Adapter->nBusySend >= 0);
  782. }
  783. /*++
  784. Routine Description:
  785. Disable the existing capabilities before protocol is setting the
  786. new capabilities
  787. Arguments:
  788. Adapter Pointer to our adapter
  789. Return Value:
  790. None
  791. --*/
  792. VOID DisableOffload(
  793. IN PMP_ADAPTER Adapter
  794. )
  795. {
  796. //
  797. // Disable the capabilities of the miniports
  798. //
  799. NdisZeroMemory(&(Adapter->NicTaskOffload), sizeof(NIC_TASK_OFFLOAD));
  800. NdisZeroMemory(&(Adapter->NicChecksumOffload), sizeof(NIC_CHECKSUM_OFFLOAD));
  801. }
  802. #endif // OFFLOAD