Leaked source code of windows server 2003
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.

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