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.

4980 lines
186 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. Send.c
  5. Abstract:
  6. This module implements Send routines
  7. the PGM Transport
  8. Author:
  9. Mohammad Shabbir Alam (MAlam) 3-30-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. //******************* Pageable Routine Declarations ****************
  14. #ifdef ALLOC_PRAGMA
  15. #endif
  16. //******************* Pageable Routine Declarations ****************
  17. //----------------------------------------------------------------------------
  18. NTSTATUS
  19. InitDataSpmOptions(
  20. IN tCOMMON_SESSION_CONTEXT *pSession,
  21. IN tCLIENT_SEND_REQUEST *pSendContext,
  22. IN PUCHAR pOptions,
  23. IN OUT USHORT *pBufferSize,
  24. IN ULONG PgmOptionsFlag,
  25. IN tPACKET_OPTIONS *pPacketOptions
  26. )
  27. /*++
  28. Routine Description:
  29. This routine initializes the header options for Data and Spm packets
  30. Arguments:
  31. IN pOptions -- Options buffer
  32. IN OUT pBufferSize -- IN Maximum packet size, OUT Options length
  33. IN PgmOptionsFlag -- Options requested to be set by caller
  34. IN pPacketOptions -- Data for specific options
  35. IN pSendContext -- Context for this send
  36. Return Value:
  37. NTSTATUS - Final status of the call
  38. --*/
  39. {
  40. ULONG pOptionsData[3];
  41. USHORT OptionsLength = 0;
  42. USHORT MaxBufferSize = *pBufferSize;
  43. tPACKET_OPTION_GENERIC UNALIGNED *pOptionHeader;
  44. tPACKET_OPTION_LENGTH UNALIGNED *pLengthOption = (tPACKET_OPTION_LENGTH UNALIGNED *) pOptions;
  45. //
  46. // Set the Packet Extension information
  47. //
  48. OptionsLength += PGM_PACKET_EXTENSION_LENGTH;
  49. if (OptionsLength > MaxBufferSize)
  50. {
  51. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  52. "Not enough space for HeaderExtension! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  53. return (STATUS_INVALID_BLOCK_LENGTH);
  54. }
  55. pLengthOption->Type = PACKET_OPTION_LENGTH;
  56. pLengthOption->Length = PGM_PACKET_EXTENSION_LENGTH;
  57. //
  58. // First fill in the Network-Element-specific options:
  59. //
  60. if (PgmOptionsFlag & (PGM_OPTION_FLAG_CRQST | PGM_OPTION_FLAG_NBR_UNREACH))
  61. {
  62. // Not supporting these options for now
  63. ASSERT (0);
  64. return (STATUS_NOT_SUPPORTED);
  65. }
  66. if (PgmOptionsFlag & PGM_OPTION_FLAG_PARITY_PRM)
  67. {
  68. //
  69. // Applies to SPMs only
  70. //
  71. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  72. OptionsLength += PGM_PACKET_OPT_PARITY_PRM_LENGTH;
  73. if (OptionsLength > MaxBufferSize)
  74. {
  75. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  76. "Not enough space for PARITY_PRM Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  77. return (STATUS_INVALID_BLOCK_LENGTH);
  78. }
  79. pOptionHeader->E_OptionType = PACKET_OPTION_PARITY_PRM;
  80. pOptionHeader->OptionLength = PGM_PACKET_OPT_PARITY_PRM_LENGTH;
  81. pOptionHeader->U_OptSpecific = pSession->FECOptions;
  82. pOptionsData[0] = htonl (pPacketOptions->FECContext.FECGroupInfo);
  83. PgmCopyMemory ((pOptionHeader + 1), pOptionsData, (sizeof(ULONG)));
  84. }
  85. if (PgmOptionsFlag & PGM_OPTION_FLAG_PARITY_CUR_TGSIZE)
  86. {
  87. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  88. OptionsLength += PGM_PACKET_OPT_PARITY_CUR_TGSIZE_LENGTH;
  89. if (OptionsLength > MaxBufferSize)
  90. {
  91. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  92. "Not enough space for PARITY_CUR_TGSIZE Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  93. return (STATUS_INVALID_BLOCK_LENGTH);
  94. }
  95. pOptionHeader->E_OptionType = PACKET_OPTION_CURR_TGSIZE;
  96. pOptionHeader->OptionLength = PGM_PACKET_OPT_PARITY_CUR_TGSIZE_LENGTH;
  97. pOptionsData[0] = htonl (pPacketOptions->FECContext.NumPacketsInThisGroup);
  98. PgmCopyMemory ((pOptionHeader + 1), pOptionsData, (sizeof(ULONG)));
  99. }
  100. //
  101. // Now, fill in the non-Network significant options
  102. //
  103. if (PgmOptionsFlag & PGM_OPTION_FLAG_SYN)
  104. {
  105. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  106. OptionsLength += PGM_PACKET_OPT_SYN_LENGTH;
  107. if (OptionsLength > MaxBufferSize)
  108. {
  109. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  110. "Not enough space for SYN Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  111. return (STATUS_INVALID_BLOCK_LENGTH);
  112. }
  113. pOptionHeader->E_OptionType = PACKET_OPTION_SYN;
  114. pOptionHeader->OptionLength = PGM_PACKET_OPT_SYN_LENGTH;
  115. if ((pSendContext) &&
  116. (pSendContext->DataOptions & PGM_OPTION_FLAG_SYN))
  117. {
  118. //
  119. // Remove this option once it has been used!
  120. //
  121. pSendContext->DataOptions &= ~PGM_OPTION_FLAG_SYN;
  122. pSendContext->DataOptionsLength -= PGM_PACKET_OPT_SYN_LENGTH;
  123. if (!pSendContext->DataOptions)
  124. {
  125. // No other options, so set the length to 0
  126. pSendContext->DataOptionsLength = 0;
  127. }
  128. }
  129. }
  130. if (PgmOptionsFlag & PGM_OPTION_FLAG_FIN)
  131. {
  132. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  133. OptionsLength += PGM_PACKET_OPT_FIN_LENGTH;
  134. if (OptionsLength > MaxBufferSize)
  135. {
  136. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  137. "Not enough space for FIN Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  138. return (STATUS_INVALID_BLOCK_LENGTH);
  139. }
  140. pOptionHeader->E_OptionType = PACKET_OPTION_FIN;
  141. pOptionHeader->OptionLength = PGM_PACKET_OPT_FIN_LENGTH;
  142. }
  143. if (PgmOptionsFlag & (PGM_OPTION_FLAG_RST | PGM_OPTION_FLAG_RST_N))
  144. {
  145. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  146. OptionsLength += PGM_PACKET_OPT_RST_LENGTH;
  147. if (OptionsLength > MaxBufferSize)
  148. {
  149. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  150. "Not enough space for RST Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  151. return (STATUS_INVALID_BLOCK_LENGTH);
  152. }
  153. pOptionHeader->E_OptionType = PACKET_OPTION_RST;
  154. pOptionHeader->OptionLength = PGM_PACKET_OPT_RST_LENGTH;
  155. if (PgmOptionsFlag & PGM_OPTION_FLAG_RST_N)
  156. {
  157. pOptionHeader->U_OptSpecific = PACKET_OPTION_SPECIFIC_RST_N_BIT;
  158. }
  159. }
  160. //
  161. // now, set the FEC-specific options
  162. //
  163. if (PgmOptionsFlag & PGM_OPTION_FLAG_PARITY_GRP)
  164. {
  165. //
  166. // Applies to Parity packets only
  167. //
  168. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  169. OptionsLength += PGM_PACKET_OPT_PARITY_GRP_LENGTH;
  170. if (OptionsLength > MaxBufferSize)
  171. {
  172. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  173. "Not enough space for PARITY_GRP Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  174. return (STATUS_INVALID_BLOCK_LENGTH);
  175. }
  176. pOptionHeader->E_OptionType = PACKET_OPTION_PARITY_GRP;
  177. pOptionHeader->OptionLength = PGM_PACKET_OPT_PARITY_GRP_LENGTH;
  178. pOptionsData[0] = htonl (pPacketOptions->FECContext.FECGroupInfo);
  179. PgmCopyMemory ((pOptionHeader + 1), pOptionsData, (sizeof(ULONG)));
  180. }
  181. //
  182. // The following options should always be at the end, since they
  183. // are never net-sig.
  184. //
  185. if (PgmOptionsFlag & PGM_OPTION_FLAG_FRAGMENT)
  186. {
  187. pPacketOptions->FragmentOptionOffset = OptionsLength;
  188. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  189. OptionsLength += PGM_PACKET_OPT_FRAGMENT_LENGTH;
  190. if (OptionsLength > MaxBufferSize)
  191. {
  192. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  193. "Not enough space for FragmentExtension! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  194. return (STATUS_INVALID_BLOCK_LENGTH);
  195. }
  196. pOptionHeader->E_OptionType = PACKET_OPTION_FRAGMENT;
  197. pOptionHeader->OptionLength = PGM_PACKET_OPT_FRAGMENT_LENGTH;
  198. //
  199. // The PACKET_OPTION_RES_F_OPX_ENCODED_BIT will be set if necessary
  200. // later since the OptionSpecific component is computed at the same
  201. // time the entire data is encoded
  202. //
  203. pOptionsData[0] = htonl ((ULONG) pPacketOptions->MessageFirstSequence);
  204. pOptionsData[1] = htonl (pPacketOptions->MessageOffset);
  205. pOptionsData[2] = htonl (pPacketOptions->MessageLength);
  206. PgmCopyMemory ((pOptionHeader + 1), pOptionsData, (3 * sizeof(ULONG)));
  207. }
  208. if (PgmOptionsFlag & PGM_OPTION_FLAG_JOIN)
  209. {
  210. pPacketOptions->LateJoinerOptionOffset = OptionsLength;
  211. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &pOptions[OptionsLength];
  212. OptionsLength += PGM_PACKET_OPT_JOIN_LENGTH;
  213. if (OptionsLength > MaxBufferSize)
  214. {
  215. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmOptions",
  216. "Not enough space for JOIN Option! <%d> > <%d>\n", OptionsLength, MaxBufferSize);
  217. return (STATUS_INVALID_BLOCK_LENGTH);
  218. }
  219. pOptionHeader->E_OptionType = PACKET_OPTION_JOIN;
  220. pOptionHeader->OptionLength = PGM_PACKET_OPT_JOIN_LENGTH;
  221. pOptionsData[0] = htonl ((ULONG) (SEQ_TYPE) pPacketOptions->LateJoinerSequence);
  222. PgmCopyMemory ((pOptionHeader + 1), pOptionsData, (sizeof(ULONG)));
  223. }
  224. //
  225. // So far, so good -- so set the rest of the option-specific info
  226. //
  227. if (OptionsLength)
  228. {
  229. pLengthOption->TotalOptionsLength = htons (OptionsLength); // Total length of all options
  230. pOptionHeader->E_OptionType |= PACKET_OPTION_TYPE_END_BIT; // Indicates the last option
  231. }
  232. *pBufferSize = OptionsLength;
  233. return (STATUS_SUCCESS);
  234. }
  235. //----------------------------------------------------------------------------
  236. NTSTATUS
  237. InitDataSpmHeader(
  238. IN tCOMMON_SESSION_CONTEXT *pSession,
  239. IN tCLIENT_SEND_REQUEST *pSendContext,
  240. IN PUCHAR pHeader,
  241. IN OUT USHORT *pHeaderLength,
  242. IN ULONG PgmOptionsFlag,
  243. IN tPACKET_OPTIONS *pPacketOptions,
  244. IN UCHAR PacketType
  245. )
  246. /*++
  247. Routine Description:
  248. This routine initializes most of the header for Data and Spm packets
  249. and fills in all of the optional fields
  250. Arguments:
  251. IN pSession -- Pgm session (sender) context
  252. IN pHeader -- Packet buffer
  253. IN pHeaderLength -- Maximum packet size
  254. IN PgmOptionsFlag -- Options requested to be set by caller
  255. IN pPacketOptions -- Data for specific options
  256. IN PacketType -- whether Data or Spm packet
  257. Return Value:
  258. NTSTATUS - Final status of the call
  259. --*/
  260. {
  261. tCOMMON_HEADER *pCommonHeader = (tCOMMON_HEADER *) pHeader;
  262. USHORT HeaderLength;
  263. USHORT OptionsLength;
  264. NTSTATUS status = STATUS_SUCCESS;
  265. // NOTE: Session Lock must be held on Entry and Exit!
  266. if (!(PGM_VERIFY_HANDLE2 (pSession, PGM_VERIFY_SESSION_SEND, PGM_VERIFY_SESSION_DOWN)))
  267. {
  268. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  269. "Bad Session ptr = <%p>\n", pSession);
  270. return (STATUS_UNSUCCESSFUL);
  271. }
  272. //
  273. // Memory for the Header must have been pre-allocated by the caller
  274. //
  275. if (*pHeaderLength < sizeof (tCOMMON_HEADER))
  276. {
  277. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  278. "InBufferLength = <%x> < Min = <%d>\n", *pHeaderLength, sizeof (tCOMMON_HEADER));
  279. return (STATUS_INVALID_BUFFER_SIZE);
  280. }
  281. pCommonHeader->SrcPort = htons (pSession->TSIPort);
  282. pCommonHeader->DestPort = htons (pSession->pSender->DestMCastPort);
  283. pCommonHeader->Type = PacketType;
  284. pCommonHeader->Options = 0;
  285. PgmCopyMemory (&pCommonHeader->gSourceId, &pSession->GSI, SOURCE_ID_LENGTH);
  286. //
  287. // Now, set the initial header size and verify that we have a
  288. // valid set of options based on the Packet type
  289. //
  290. switch (PacketType)
  291. {
  292. case (PACKET_TYPE_SPM):
  293. {
  294. HeaderLength = sizeof (tBASIC_SPM_PACKET_HEADER);
  295. if (PgmOptionsFlag != (PGM_VALID_SPM_OPTION_FLAGS & PgmOptionsFlag))
  296. {
  297. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  298. "Unsupported Options flags=<%x> for SPM packets\n", PgmOptionsFlag);
  299. return (STATUS_INVALID_PARAMETER);
  300. }
  301. if (PgmOptionsFlag & NETWORK_SIG_SPM_OPTIONS_FLAGS)
  302. {
  303. pCommonHeader->Options |= PACKET_HEADER_OPTIONS_NETWORK_SIGNIFICANT;
  304. }
  305. break;
  306. }
  307. case (PACKET_TYPE_ODATA):
  308. {
  309. HeaderLength = sizeof (tBASIC_DATA_PACKET_HEADER);
  310. if (PgmOptionsFlag != (PGM_VALID_DATA_OPTION_FLAGS & PgmOptionsFlag))
  311. {
  312. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  313. "Unsupported Options flags=<%x> for ODATA packets\n", PgmOptionsFlag);
  314. return (STATUS_INVALID_PARAMETER);
  315. }
  316. if (PgmOptionsFlag & NETWORK_SIG_ODATA_OPTIONS_FLAGS)
  317. {
  318. pCommonHeader->Options |= PACKET_HEADER_OPTIONS_NETWORK_SIGNIFICANT;
  319. }
  320. break;
  321. }
  322. case (PACKET_TYPE_RDATA):
  323. {
  324. HeaderLength = sizeof (tBASIC_DATA_PACKET_HEADER);
  325. if (PgmOptionsFlag != (PGM_VALID_DATA_OPTION_FLAGS & PgmOptionsFlag))
  326. {
  327. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  328. "Unsupported Options flags=<%x> for RDATA packets\n", PgmOptionsFlag);
  329. return (STATUS_INVALID_PARAMETER);
  330. }
  331. if (PgmOptionsFlag & NETWORK_SIG_RDATA_OPTIONS_FLAGS)
  332. {
  333. pCommonHeader->Options |= PACKET_HEADER_OPTIONS_NETWORK_SIGNIFICANT;
  334. }
  335. break;
  336. }
  337. default:
  338. {
  339. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  340. "Unsupported packet type = <%x>\n", PacketType);
  341. return (STATUS_INVALID_PARAMETER); // Unrecognized Packet type!
  342. }
  343. }
  344. if (*pHeaderLength < HeaderLength)
  345. {
  346. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  347. "InBufferLength=<%x> < HeaderLength=<%d> based on PacketType=<%x>\n",
  348. *pHeaderLength, HeaderLength, PacketType);
  349. return (STATUS_INVALID_BLOCK_LENGTH);
  350. }
  351. //
  352. // Add any options if specified
  353. //
  354. OptionsLength = 0;
  355. if (PgmOptionsFlag)
  356. {
  357. OptionsLength = *pHeaderLength - HeaderLength;
  358. status = InitDataSpmOptions (pSession,
  359. pSendContext,
  360. &pHeader[HeaderLength],
  361. &OptionsLength,
  362. PgmOptionsFlag,
  363. pPacketOptions);
  364. if (!NT_SUCCESS (status))
  365. {
  366. PgmLog (PGM_LOG_ERROR, DBG_SEND, "InitDataSpmHeader",
  367. "InitDataSpmOptions returned <%x>\n", status);
  368. return (status);
  369. }
  370. //
  371. // So far, so good -- so set the rest of the option-specific info
  372. //
  373. pCommonHeader->Options |= PACKET_HEADER_OPTIONS_PRESENT; // Set the options bit
  374. }
  375. //
  376. // The caller must now set the Checksum and other header information
  377. //
  378. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "InitDataSpmHeader",
  379. "pHeader=<%p>, HeaderLength=<%d>, OptionsLength=<%d>\n",
  380. pHeader, (ULONG) HeaderLength, (ULONG) OptionsLength);
  381. *pHeaderLength = HeaderLength + OptionsLength;
  382. return (STATUS_SUCCESS);
  383. }
  384. //----------------------------------------------------------------------------
  385. VOID
  386. PgmSendSpmCompletion(
  387. IN tSEND_SESSION *pSend,
  388. IN tBASIC_SPM_PACKET_HEADER *pSpmPacket,
  389. IN NTSTATUS status
  390. )
  391. /*++
  392. Routine Description:
  393. This routine is called by the transport when the Spm send has been completed
  394. Arguments:
  395. IN pSend -- Pgm session (sender) context
  396. IN pSpmPacket -- Spm packet buffer
  397. IN status --
  398. Return Value:
  399. NONE
  400. --*/
  401. {
  402. PGMLockHandle OldIrq;
  403. PgmLock (pSend, OldIrq);
  404. if (NT_SUCCESS (status))
  405. {
  406. //
  407. // Set the Spm statistics
  408. //
  409. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendSpmCompletion",
  410. "SUCCEEDED\n");
  411. }
  412. else
  413. {
  414. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendSpmCompletion",
  415. "status=<%x>\n", status);
  416. }
  417. PgmUnlock (pSend, OldIrq);
  418. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_SPM);
  419. //
  420. // Free the Memory that was allocated for this
  421. //
  422. PgmFreeMem (pSpmPacket);
  423. }
  424. //----------------------------------------------------------------------------
  425. NTSTATUS
  426. PgmSendSpm(
  427. IN tSEND_SESSION *pSend,
  428. IN PGMLockHandle *pOldIrq,
  429. OUT ULONG *pBytesSent
  430. )
  431. /*++
  432. Routine Description:
  433. This routine is called to send an Spm packet
  434. The pSend lock is held before calling this routine
  435. Arguments:
  436. IN pSend -- Pgm session (sender) context
  437. IN pOldIrq -- pSend's OldIrq
  438. OUT pBytesSent -- Set if send succeeded (used for calculating throughput)
  439. Return Value:
  440. NTSTATUS - Final status of the send
  441. --*/
  442. {
  443. NTSTATUS status;
  444. ULONG XSum, OptionsFlags;
  445. tBASIC_SPM_PACKET_HEADER *pSpmPacket = NULL;
  446. tPACKET_OPTIONS PacketOptions;
  447. USHORT PacketLength = (USHORT) pSend->pSender->pAddress->OutIfMTU; // Init to max
  448. *pBytesSent = 0;
  449. if (!(pSpmPacket = PgmAllocMem (PacketLength, PGM_TAG('2'))))
  450. {
  451. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendSpm",
  452. "STATUS_INSUFFICIENT_RESOURCES\n");
  453. return (STATUS_INSUFFICIENT_RESOURCES);
  454. }
  455. PgmZeroMemory (pSpmPacket, PacketLength);
  456. PgmZeroMemory (&PacketOptions, sizeof(tPACKET_OPTIONS));
  457. OptionsFlags = pSend->pSender->SpmOptions;
  458. if (OptionsFlags & PGM_OPTION_FLAG_JOIN)
  459. {
  460. //
  461. // See if we have enough packets for the LateJoiner sequence numbers
  462. //
  463. if (SEQ_GT (pSend->pSender->LastODataSentSequenceNumber, (pSend->pSender->TrailingGroupSequenceNumber +
  464. pSend->pSender->LateJoinSequenceNumbers)))
  465. {
  466. PacketOptions.LateJoinerSequence = (ULONG) (SEQ_TYPE) (pSend->pSender->LastODataSentSequenceNumber -
  467. pSend->pSender->LateJoinSequenceNumbers);
  468. }
  469. else
  470. {
  471. PacketOptions.LateJoinerSequence = (ULONG) (SEQ_TYPE) pSend->pSender->TrailingGroupSequenceNumber;
  472. }
  473. }
  474. if (OptionsFlags & PGM_OPTION_FLAG_PARITY_PRM) // Check if this is FEC-enabled
  475. {
  476. PacketOptions.FECContext.FECGroupInfo = pSend->FECGroupSize;
  477. //
  478. // See if we need to set the CURR_TGSIZE option for variable Group length
  479. //
  480. if ((pSend->pSender->EmptySequencesForLastSend) &&
  481. (pSend->pSender->LastVariableTGPacketSequenceNumber ==
  482. (pSend->pSender->LastODataSentSequenceNumber - pSend->pSender->EmptySequencesForLastSend)))
  483. {
  484. PacketOptions.FECContext.NumPacketsInThisGroup = pSend->FECGroupSize -
  485. (UCHAR)pSend->pSender->EmptySequencesForLastSend;
  486. OptionsFlags |= PGM_OPTION_FLAG_PARITY_CUR_TGSIZE;
  487. ASSERT (PacketOptions.FECContext.NumPacketsInThisGroup);
  488. }
  489. }
  490. status = InitDataSpmHeader (pSend,
  491. NULL,
  492. (PUCHAR) pSpmPacket,
  493. &PacketLength,
  494. OptionsFlags,
  495. &PacketOptions,
  496. PACKET_TYPE_SPM);
  497. if (!NT_SUCCESS (status))
  498. {
  499. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendSpm",
  500. "InitDataSpmHeader returned <%x>\n", status);
  501. PgmFreeMem (pSpmPacket);
  502. return (status);
  503. }
  504. ASSERT (PacketLength);
  505. pSpmPacket->SpmSequenceNumber = htonl ((ULONG) pSend->pSender->NextSpmSequenceNumber++);
  506. pSpmPacket->TrailingEdgeSeqNumber = htonl ((ULONG) pSend->pSender->TrailingGroupSequenceNumber);
  507. pSpmPacket->LeadingEdgeSeqNumber = htonl ((ULONG)((SEQ_TYPE)(pSend->pSender->LastODataSentSequenceNumber -
  508. pSend->pSender->EmptySequencesForLastSend)));
  509. pSpmPacket->PathNLA.NLA_AFI = htons (IPV4_NLA_AFI);
  510. pSpmPacket->PathNLA.IpAddress = htonl (pSend->pSender->SenderMCastOutIf);
  511. pSpmPacket->CommonHeader.Checksum = 0;
  512. XSum = 0;
  513. XSum = tcpxsum (XSum, (CHAR *) pSpmPacket, PacketLength); // Compute the Checksum
  514. pSpmPacket->CommonHeader.Checksum = (USHORT) (~XSum);
  515. PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_SPM, TRUE);
  516. PgmUnlock (pSend, *pOldIrq);
  517. status = TdiSendDatagram (pSend->pSender->pAddress->pRAlertFileObject,
  518. pSend->pSender->pAddress->pRAlertDeviceObject,
  519. pSpmPacket,
  520. PacketLength,
  521. PgmSendSpmCompletion, // Completion
  522. pSend, // Context1
  523. pSpmPacket, // Context2
  524. pSend->pSender->DestMCastIpAddress,
  525. pSend->pSender->DestMCastPort);
  526. ASSERT (NT_SUCCESS (status));
  527. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendSpm",
  528. "Sent <%d> bytes to <%x:%d>, Options=<%x>, Window=[%d--%d]\n",
  529. (ULONG) PacketLength, pSend->pSender->DestMCastIpAddress, pSend->pSender->DestMCastPort,
  530. OptionsFlags, (ULONG) pSend->pSender->TrailingGroupSequenceNumber,
  531. (ULONG) pSend->pSender->LastODataSentSequenceNumber);
  532. PgmLock (pSend, *pOldIrq);
  533. *pBytesSent = PacketLength;
  534. return (status);
  535. }
  536. //----------------------------------------------------------------------------
  537. VOID
  538. PgmSendRDataCompletion(
  539. IN tSEND_RDATA_CONTEXT *pRDataContext,
  540. IN PVOID pRDataBuffer,
  541. IN NTSTATUS status
  542. )
  543. /*++
  544. Routine Description:
  545. This routine is called by the transport when the RData send has been completed
  546. Arguments:
  547. IN pRDataContext -- RData context
  548. IN pContext2 -- not used
  549. IN status --
  550. Return Value:
  551. NONE
  552. --*/
  553. {
  554. tSEND_SESSION *pSend = pRDataContext->pSend;
  555. PGMLockHandle OldIrq;
  556. ASSERT (NT_SUCCESS (status));
  557. //
  558. // Set the RData statistics
  559. //
  560. PgmLock (pSend, OldIrq);
  561. if ((!--pRDataContext->NumPacketsInTransport) &&
  562. (!pRDataContext->NumNaks))
  563. {
  564. pRDataContext->CleanupTime = pSend->pSender->TimerTickCount + pRDataContext->PostRDataHoldTime;
  565. }
  566. PgmUnlock (pSend, OldIrq);
  567. if (pRDataBuffer)
  568. {
  569. ExFreeToNPagedLookasideList (&pSend->pSender->SenderBufferLookaside, pRDataBuffer);
  570. }
  571. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendRDataCompletion",
  572. "status=<%x>, pRDataBuffer=<%p>\n", status, pRDataBuffer);
  573. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_RDATA);
  574. return;
  575. }
  576. //----------------------------------------------------------------------------
  577. NTSTATUS
  578. PgmBuildParityPacket(
  579. IN tSEND_SESSION *pSend,
  580. IN tPACKET_BUFFER *pPacketBuffer,
  581. IN tBUILD_PARITY_CONTEXT *pParityContext,
  582. IN PUCHAR pFECPacket,
  583. IN OUT USHORT *pPacketLength,
  584. IN UCHAR PacketType
  585. )
  586. {
  587. NTSTATUS status;
  588. tPACKET_OPTIONS PacketOptions;
  589. tPOST_PACKET_FEC_CONTEXT UNALIGNED *pFECContext;
  590. tPOST_PACKET_FEC_CONTEXT FECContext;
  591. ULONG SequenceNumber;
  592. ULONG FECGroupMask;
  593. tPACKET_OPTION_GENERIC UNALIGNED *pOptionHeader;
  594. USHORT PacketLength = *pPacketLength; // Init to max buffer length
  595. tBASIC_DATA_PACKET_HEADER UNALIGNED *pRData = (tBASIC_DATA_PACKET_HEADER UNALIGNED *)
  596. &pPacketBuffer->DataPacket;
  597. *pPacketLength = 0; // Init, in case of error
  598. //
  599. // First, get the options encoded in this RData packet to see
  600. // if we need to use them!
  601. //
  602. FECGroupMask = pSend->FECGroupSize - 1;
  603. pParityContext->NextFECPacketIndex = pPacketBuffer->PacketOptions.FECContext.SenderNextFECPacketIndex;
  604. SequenceNumber = (ntohl(pRData->DataSequenceNumber)) | (pParityContext->NextFECPacketIndex & FECGroupMask);
  605. ASSERT (!(pParityContext->OptionsFlags & ~(PGM_OPTION_FLAG_SYN |
  606. PGM_OPTION_FLAG_FIN |
  607. PGM_OPTION_FLAG_FRAGMENT |
  608. PGM_OPTION_FLAG_PARITY_CUR_TGSIZE |
  609. PGM_OPTION_FLAG_PARITY_GRP)));
  610. PgmZeroMemory (&PacketOptions, sizeof (tPACKET_OPTIONS));
  611. //
  612. // We don't need to set any parameters for the SYN and FIN options
  613. // We will set the parameters for the FRAGMENT option (if needed) later
  614. // since will need to have the encoded paramters
  615. //
  616. if (pParityContext->OptionsFlags & PGM_OPTION_FLAG_PARITY_CUR_TGSIZE)
  617. {
  618. ASSERT (pParityContext->NumPacketsInThisGroup);
  619. PacketOptions.FECContext.NumPacketsInThisGroup = pParityContext->NumPacketsInThisGroup;
  620. }
  621. if (pParityContext->NextFECPacketIndex >= pSend->FECGroupSize)
  622. {
  623. pParityContext->OptionsFlags |= PGM_OPTION_FLAG_PARITY_GRP;
  624. PacketOptions.FECContext.FECGroupInfo = pParityContext->NextFECPacketIndex / pSend->FECGroupSize;
  625. }
  626. PgmZeroMemory (pFECPacket, PacketLength);
  627. status = InitDataSpmHeader (pSend,
  628. NULL,
  629. (PUCHAR) pFECPacket,
  630. &PacketLength,
  631. pParityContext->OptionsFlags,
  632. &PacketOptions,
  633. PacketType);
  634. if (!NT_SUCCESS (status))
  635. {
  636. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmBuildParityPacket",
  637. "InitDataSpmHeader returned <%x>\n", status);
  638. return (status);
  639. }
  640. status = FECEncode (&pSend->FECContext,
  641. &pParityContext->pDataBuffers[0],
  642. pParityContext->NumPacketsInThisGroup,
  643. (pSend->pSender->MaxPayloadSize + sizeof (tPOST_PACKET_FEC_CONTEXT)),
  644. pParityContext->NextFECPacketIndex,
  645. &pFECPacket[PacketLength]);
  646. if (!NT_SUCCESS (status))
  647. {
  648. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmBuildParityPacket",
  649. "FECEncode returned <%x>\n", status);
  650. return (status);
  651. }
  652. //
  653. // Now, fill in the remaining fields of the header
  654. //
  655. pRData = (tBASIC_DATA_PACKET_HEADER *) pFECPacket;
  656. //
  657. // Set the FEC-specific options
  658. //
  659. pRData->CommonHeader.Options |= (PACKET_HEADER_OPTIONS_PARITY |
  660. PACKET_HEADER_OPTIONS_VAR_PKTLEN);
  661. if (pParityContext->OptionsFlags & PGM_OPTION_FLAG_FRAGMENT)
  662. {
  663. pFECContext = (tPOST_PACKET_FEC_CONTEXT UNALIGNED *) (pFECPacket +
  664. PacketLength +
  665. pSend->pSender->MaxPayloadSize);
  666. PgmCopyMemory (&FECContext, pFECContext, sizeof (tPOST_PACKET_FEC_CONTEXT));
  667. ASSERT (pRData->CommonHeader.Options & PACKET_HEADER_OPTIONS_PRESENT);
  668. if (PacketOptions.FragmentOptionOffset)
  669. {
  670. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &((PUCHAR) (pRData + 1)) [PacketOptions.FragmentOptionOffset];
  671. pOptionHeader->Reserved_F_Opx |= PACKET_OPTION_RES_F_OPX_ENCODED_BIT;
  672. pOptionHeader->U_OptSpecific = FECContext.FragmentOptSpecific;
  673. PgmCopyMemory ((pOptionHeader + 1),
  674. &FECContext.EncodedFragmentOptions,
  675. (sizeof (tFRAGMENT_OPTIONS)));
  676. }
  677. else
  678. {
  679. ASSERT (0);
  680. }
  681. }
  682. pRData->CommonHeader.TSDULength = htons ((USHORT) pSend->pSender->MaxPayloadSize + sizeof (USHORT));
  683. pRData->DataSequenceNumber = htonl (SequenceNumber);
  684. //
  685. // Set the next FECPacketIndex
  686. //
  687. if (++pParityContext->NextFECPacketIndex >= pSend->FECBlockSize) // n
  688. {
  689. pParityContext->NextFECPacketIndex = pSend->FECGroupSize; // k
  690. }
  691. pPacketBuffer->PacketOptions.FECContext.SenderNextFECPacketIndex = pParityContext->NextFECPacketIndex;
  692. PacketLength += (USHORT) (pSend->pSender->MaxPayloadSize + sizeof (USHORT));
  693. *pPacketLength = PacketLength;
  694. return (status);
  695. }
  696. //----------------------------------------------------------------------------
  697. NTSTATUS
  698. PgmSendRData(
  699. IN tSEND_SESSION *pSend,
  700. IN tSEND_RDATA_CONTEXT *pRDataContext,
  701. IN PGMLockHandle *pOldIrq,
  702. OUT ULONG *pBytesSent
  703. )
  704. /*++
  705. Routine Description:
  706. This routine is called to send a Repair Data (RData) packet
  707. The pSend lock is held before calling this routine
  708. Arguments:
  709. IN pSend -- Pgm session (sender) context
  710. IN pOldIrq -- pSend's OldIrq
  711. OUT pBytesSent -- Set if send succeeded (used for calculating throughput)
  712. Arguments:
  713. IN
  714. Return Value:
  715. NTSTATUS - Final status of the send request
  716. --*/
  717. {
  718. NTSTATUS status;
  719. KAPC_STATE ApcState;
  720. BOOLEAN fAttached, fInserted;
  721. LIST_ENTRY *pEntry;
  722. ULONGLONG OffsetBytes;
  723. ULONG XSum, PacketsBehindLeadingEdge;
  724. tBASIC_DATA_PACKET_HEADER *pRData;
  725. PUCHAR pSendBuffer = NULL;
  726. USHORT i, PacketLength;
  727. tPACKET_BUFFER *pPacketBuffer;
  728. tPACKET_BUFFER *pPacketBufferTemp;
  729. tSEND_RDATA_CONTEXT *pRDataTemp;
  730. *pBytesSent = 0;
  731. ASSERT (SEQ_LEQ (pRDataContext->RDataSequenceNumber, pSend->pSender->LastODataSentSequenceNumber) &&
  732. SEQ_GEQ (pRDataContext->RDataSequenceNumber, pSend->pSender->TrailingGroupSequenceNumber));
  733. //
  734. // Find the buffer address based on offset from the trailing edge
  735. // Also, check for wrap-around
  736. //
  737. OffsetBytes = (SEQ_TYPE) (pRDataContext->RDataSequenceNumber-pSend->pSender->TrailingEdgeSequenceNumber) *
  738. pSend->pSender->PacketBufferSize;
  739. OffsetBytes += pSend->pSender->TrailingWindowOffset;
  740. if (OffsetBytes >= pSend->pSender->MaxDataFileSize)
  741. {
  742. OffsetBytes -= pSend->pSender->MaxDataFileSize; // Wrap -around
  743. }
  744. pPacketBuffer = (tPACKET_BUFFER *) (((PUCHAR) pSend->pSender->SendDataBufferMapping) + OffsetBytes);
  745. pRData = &pPacketBuffer->DataPacket;
  746. ASSERT (PGM_MAX_FEC_DATA_HEADER_LENGTH >= PGM_MAX_DATA_HEADER_LENGTH);
  747. PacketLength = PGM_MAX_FEC_DATA_HEADER_LENGTH + (USHORT) pSend->pSender->MaxPayloadSize;
  748. if (!(pSendBuffer = ExAllocateFromNPagedLookasideList (&pSend->pSender->SenderBufferLookaside)))
  749. {
  750. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendRData",
  751. "STATUS_INSUFFICIENT_RESOURCES\n");
  752. return (STATUS_INSUFFICIENT_RESOURCES);
  753. }
  754. //
  755. // First do some sanity checks!
  756. //
  757. ASSERT ((pRDataContext->NakType == NAK_TYPE_PARITY) ||
  758. (pRDataContext->NumNaks == 1));
  759. pRDataContext->NumPacketsInTransport++; // So that this context cannot go away!
  760. PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_RDATA, TRUE);
  761. PgmUnlock (pSend, *pOldIrq);
  762. PgmAttachToProcessForVMAccess (pSend, &ApcState, &fAttached, REF_PROCESS_ATTACH_SEND_RDATA);
  763. switch (pRDataContext->NakType)
  764. {
  765. case (NAK_TYPE_PARITY):
  766. {
  767. //
  768. // If this is the first parity packet to be sent from this group,
  769. // then we will need to initialize the buffers
  770. //
  771. if (!pRDataContext->OnDemandParityContext.NumPacketsInThisGroup)
  772. {
  773. pRDataContext->OnDemandParityContext.OptionsFlags = 0;
  774. pRDataContext->OnDemandParityContext.NumPacketsInThisGroup = 0;
  775. pPacketBufferTemp = pPacketBuffer;
  776. for (i=0; i<pSend->FECGroupSize; i++)
  777. {
  778. pRDataContext->OnDemandParityContext.pDataBuffers[i] = &((PUCHAR) &pPacketBufferTemp->DataPacket)
  779. [sizeof (tBASIC_DATA_PACKET_HEADER) +
  780. pPacketBufferTemp->PacketOptions.OptionsLength];
  781. pRDataContext->OnDemandParityContext.OptionsFlags |= pPacketBufferTemp->PacketOptions.OptionsFlags &
  782. (PGM_OPTION_FLAG_SYN |
  783. PGM_OPTION_FLAG_FIN |
  784. PGM_OPTION_FLAG_FRAGMENT |
  785. PGM_OPTION_FLAG_PARITY_CUR_TGSIZE);
  786. if (pPacketBufferTemp->PacketOptions.OptionsFlags & PGM_OPTION_FLAG_PARITY_CUR_TGSIZE)
  787. {
  788. ASSERT (!pRDataContext->OnDemandParityContext.NumPacketsInThisGroup);
  789. ASSERT (pPacketBufferTemp->PacketOptions.FECContext.NumPacketsInThisGroup);
  790. pRDataContext->OnDemandParityContext.NumPacketsInThisGroup = pPacketBufferTemp->PacketOptions.FECContext.NumPacketsInThisGroup;
  791. }
  792. pPacketBufferTemp = (tPACKET_BUFFER *) (((PUCHAR) pPacketBufferTemp) +
  793. pSend->pSender->PacketBufferSize);
  794. }
  795. if (!(pRDataContext->OnDemandParityContext.OptionsFlags & PGM_OPTION_FLAG_PARITY_CUR_TGSIZE))
  796. {
  797. ASSERT (!pRDataContext->OnDemandParityContext.NumPacketsInThisGroup);
  798. pRDataContext->OnDemandParityContext.NumPacketsInThisGroup = pSend->FECGroupSize;
  799. }
  800. }
  801. ASSERT (pRDataContext->OnDemandParityContext.pDataBuffers[0]);
  802. //
  803. // If we have just 1 packet in this group, then we just do
  804. // a selective Nak
  805. //
  806. if (pRDataContext->OnDemandParityContext.NumPacketsInThisGroup != 1)
  807. {
  808. status = PgmBuildParityPacket (pSend,
  809. pPacketBuffer,
  810. &pRDataContext->OnDemandParityContext,
  811. pSendBuffer,
  812. &PacketLength,
  813. PACKET_TYPE_RDATA);
  814. if (!NT_SUCCESS (status))
  815. {
  816. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendRData",
  817. "PgmBuildParityPacket returned <%x>\n", status);
  818. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_SEND_RDATA);
  819. PgmLock (pSend, *pOldIrq);
  820. ExFreeToNPagedLookasideList (&pSend->pSender->SenderBufferLookaside, pSendBuffer);
  821. pRDataContext->NumPacketsInTransport--; // Undoing what we did earlier
  822. return (status);
  823. }
  824. pRData = (tBASIC_DATA_PACKET_HEADER *) pSendBuffer;
  825. break;
  826. }
  827. pRDataContext->NumNaks = 1; // Don't want to send excessive Selective naks!
  828. }
  829. case (NAK_TYPE_SELECTIVE):
  830. {
  831. //
  832. // Since the packet was already filled in earlier, we just need to
  833. // update the Trailing Edge Seq number + PacketType and Checksum!
  834. //
  835. ASSERT ((ULONG) pRDataContext->RDataSequenceNumber == (ULONG) ntohl (pRData->DataSequenceNumber));
  836. PacketLength = pPacketBuffer->PacketOptions.TotalPacketLength;
  837. PgmCopyMemory (pSendBuffer, pRData, PacketLength);
  838. pRData = (tBASIC_DATA_PACKET_HEADER *) pSendBuffer;
  839. break;
  840. }
  841. default:
  842. {
  843. ASSERT (0);
  844. }
  845. }
  846. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_SEND_RDATA);
  847. pRData->TrailingEdgeSequenceNumber = htonl ((ULONG) pSend->pSender->TrailingGroupSequenceNumber);
  848. pRData->CommonHeader.Type = PACKET_TYPE_RDATA;
  849. pRData->CommonHeader.Checksum = 0;
  850. XSum = 0;
  851. XSum = tcpxsum (XSum, (CHAR *) pRData, (ULONG) PacketLength); // Compute the Checksum
  852. pRData->CommonHeader.Checksum = (USHORT) (~XSum);
  853. status = TdiSendDatagram (pSend->pSender->pAddress->pRAlertFileObject,
  854. pSend->pSender->pAddress->pRAlertDeviceObject,
  855. pRData,
  856. (ULONG) PacketLength,
  857. PgmSendRDataCompletion, // Completion
  858. pRDataContext, // Context1
  859. pSendBuffer, // Context2
  860. pSend->pSender->DestMCastIpAddress,
  861. pSend->pSender->DestMCastPort);
  862. ASSERT (NT_SUCCESS (status));
  863. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendRData",
  864. "[%d] Sent <%d> bytes to <%x->%d>\n",
  865. (ULONG) pRDataContext->RDataSequenceNumber, (ULONG) PacketLength,
  866. pSend->pSender->DestMCastIpAddress, pSend->pSender->DestMCastPort);
  867. PgmLock (pSend, *pOldIrq);
  868. if (!--pRDataContext->NumNaks)
  869. {
  870. RemoveEntryList (&pRDataContext->Linkage);
  871. //
  872. // The Handled list has to be sorted for FilterAndAddNaksToList to work
  873. // We will traverse the list backwards since there is a higher
  874. // probability of inserting this context near the end of the list
  875. // So, we will try to find an element we can insert after
  876. //
  877. fInserted = FALSE;
  878. pEntry = &pSend->pSender->HandledRDataRequests;
  879. while ((pEntry = pEntry->Blink) != &pSend->pSender->HandledRDataRequests)
  880. {
  881. pRDataTemp = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  882. //
  883. // Sequences greater than this can be skipped
  884. //
  885. if (SEQ_GT (pRDataTemp->RDataSequenceNumber, pRDataContext->RDataSequenceNumber))
  886. {
  887. continue;
  888. }
  889. //
  890. // We will always order the Parity Nak before the Selective Nak
  891. // Both the Nak types should not exist in the list for the
  892. // same sequence number
  893. //
  894. if ((pRDataTemp->RDataSequenceNumber == pRDataContext->RDataSequenceNumber) &&
  895. (pRDataTemp->NakType == NAK_TYPE_SELECTIVE))
  896. {
  897. ASSERT (pRDataTemp->NakType != pRDataContext->NakType);
  898. continue;
  899. }
  900. pRDataContext->Linkage.Blink = pEntry;
  901. pRDataContext->Linkage.Flink = pEntry->Flink;
  902. pEntry->Flink->Blink = &pRDataContext->Linkage;
  903. pEntry->Flink = &pRDataContext->Linkage;
  904. fInserted = TRUE;
  905. break;
  906. }
  907. if (!fInserted)
  908. {
  909. InsertHeadList (&pSend->pSender->HandledRDataRequests, &pRDataContext->Linkage);
  910. }
  911. pSend->pSender->NumRDataRequestsPending--;
  912. //
  913. // If the SendCompletion was called before this point, then we will
  914. // need to set the CleanupTime outselves
  915. //
  916. if (!pRDataContext->NumPacketsInTransport)
  917. {
  918. pRDataContext->CleanupTime = pSend->pSender->TimerTickCount + pRDataContext->PostRDataHoldTime;
  919. }
  920. }
  921. pSend->pSender->NumOutstandingNaks--;
  922. pSend->pSender->RepairPacketsSent++;
  923. *pBytesSent = PacketLength;
  924. return (status);
  925. }
  926. //----------------------------------------------------------------------------
  927. VOID
  928. PgmSendNcfCompletion(
  929. IN tSEND_SESSION *pSend,
  930. IN tBASIC_NAK_NCF_PACKET_HEADER *pNcfPacket,
  931. IN NTSTATUS status
  932. )
  933. /*++
  934. Routine Description:
  935. This routine is called by the transport when the Ncf send has been completed
  936. Arguments:
  937. IN pSend -- Pgm session (sender) context
  938. IN pNcfPacket -- Ncf packet buffer
  939. IN status --
  940. Return Value:
  941. NONE
  942. --*/
  943. {
  944. PGMLockHandle OldIrq;
  945. PgmLock (pSend, OldIrq);
  946. if (NT_SUCCESS (status))
  947. {
  948. //
  949. // Set the Ncf statistics
  950. //
  951. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendNcfCompletion",
  952. "SUCCEEDED\n");
  953. }
  954. else
  955. {
  956. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendNcfCompletion",
  957. "status=<%x>\n", status);
  958. }
  959. PgmUnlock (pSend, OldIrq);
  960. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_NCF);
  961. PgmFreeMem (pNcfPacket);
  962. }
  963. //----------------------------------------------------------------------------
  964. NTSTATUS
  965. PgmSendNcf(
  966. IN tSEND_SESSION *pSend,
  967. IN tBASIC_NAK_NCF_PACKET_HEADER UNALIGNED *pNakPacket,
  968. IN tNAKS_LIST *pNcfsList,
  969. IN ULONG NakPacketLength
  970. )
  971. /*++
  972. Routine Description:
  973. This routine is called to send an NCF packet
  974. Arguments:
  975. IN pSend -- Pgm session (sender) context
  976. IN pNakPacket -- Nak packet which trigerred the Ncf
  977. IN NakPacketLength -- Length of Nak packet
  978. Return Value:
  979. NTSTATUS - Final status of the send
  980. --*/
  981. {
  982. ULONG i, XSum;
  983. NTSTATUS status;
  984. tBASIC_NAK_NCF_PACKET_HEADER *pNcfPacket;
  985. tPACKET_OPTION_LENGTH *pPacketExtension;
  986. tPACKET_OPTION_GENERIC *pOptionHeader;
  987. USHORT OptionsLength = 0;
  988. if (!(pNcfPacket = PgmAllocMem (NakPacketLength, PGM_TAG('2'))))
  989. {
  990. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendNcf",
  991. "STATUS_INSUFFICIENT_RESOURCES\n");
  992. return (STATUS_INSUFFICIENT_RESOURCES);
  993. }
  994. PgmZeroMemory (pNcfPacket, NakPacketLength); // Copy the packet in its entirety
  995. //
  996. // Now, set the fields specific to this sender
  997. //
  998. pNcfPacket->CommonHeader.SrcPort = htons (pSend->TSIPort);
  999. pNcfPacket->CommonHeader.DestPort = htons (pSend->pSender->DestMCastPort);
  1000. pNcfPacket->CommonHeader.Type = PACKET_TYPE_NCF;
  1001. if (pNcfsList->NakType == NAK_TYPE_PARITY)
  1002. {
  1003. pNcfPacket->CommonHeader.Options = PACKET_HEADER_OPTIONS_PARITY;
  1004. }
  1005. else
  1006. {
  1007. pNcfPacket->CommonHeader.Options = 0;
  1008. }
  1009. PgmCopyMemory (&pNcfPacket->CommonHeader.gSourceId, &pSend->GSI, SOURCE_ID_LENGTH);
  1010. pNcfPacket->SourceNLA.NLA_AFI = pNakPacket->SourceNLA.NLA_AFI;
  1011. pNcfPacket->SourceNLA.IpAddress = pNakPacket->SourceNLA.IpAddress;
  1012. pNcfPacket->MCastGroupNLA.NLA_AFI = pNakPacket->MCastGroupNLA.NLA_AFI;
  1013. pNcfPacket->MCastGroupNLA.IpAddress = pNakPacket->MCastGroupNLA.IpAddress;
  1014. //
  1015. // Now, fill in the Sequence numbers
  1016. //
  1017. ASSERT (pNcfsList->NumNaks[0]);
  1018. pNcfPacket->RequestedSequenceNumber = htonl ((ULONG) ((SEQ_TYPE) (pNcfsList->pNakSequences[0] +
  1019. pNcfsList->NumNaks[0] - 1)));
  1020. if (pNcfsList->NumSequences > 1)
  1021. {
  1022. pPacketExtension = (tPACKET_OPTION_LENGTH *) (pNcfPacket + 1);
  1023. pPacketExtension->Type = PACKET_OPTION_LENGTH;
  1024. pPacketExtension->Length = PGM_PACKET_EXTENSION_LENGTH;
  1025. OptionsLength += PGM_PACKET_EXTENSION_LENGTH;
  1026. pOptionHeader = (tPACKET_OPTION_GENERIC *) (pPacketExtension + 1);
  1027. pOptionHeader->E_OptionType = PACKET_OPTION_NAK_LIST;
  1028. pOptionHeader->OptionLength = 4 + (UCHAR) ((pNcfsList->NumSequences-1) * sizeof(ULONG));
  1029. for (i=1; i<pNcfsList->NumSequences; i++)
  1030. {
  1031. ASSERT (pNcfsList->NumNaks[i]);
  1032. ((PULONG) (pOptionHeader))[i] = htonl ((ULONG) ((SEQ_TYPE) (pNcfsList->pNakSequences[i] +
  1033. pNcfsList->NumNaks[i] - 1)));
  1034. }
  1035. pOptionHeader->E_OptionType |= PACKET_OPTION_TYPE_END_BIT; // One and only (last) opt
  1036. pNcfPacket->CommonHeader.Options |=(PACKET_HEADER_OPTIONS_PRESENT |
  1037. PACKET_HEADER_OPTIONS_NETWORK_SIGNIFICANT);
  1038. OptionsLength = PGM_PACKET_EXTENSION_LENGTH + pOptionHeader->OptionLength;
  1039. pPacketExtension->TotalOptionsLength = htons (OptionsLength);
  1040. }
  1041. OptionsLength += sizeof(tBASIC_NAK_NCF_PACKET_HEADER); // Now is whole pkt
  1042. pNcfPacket->CommonHeader.Checksum = 0;
  1043. XSum = 0;
  1044. XSum = tcpxsum (XSum, (CHAR *) pNcfPacket, NakPacketLength);
  1045. pNcfPacket->CommonHeader.Checksum = (USHORT) (~XSum);
  1046. PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_NCF, FALSE);
  1047. status = TdiSendDatagram (pSend->pSender->pAddress->pRAlertFileObject,
  1048. pSend->pSender->pAddress->pRAlertDeviceObject,
  1049. pNcfPacket,
  1050. OptionsLength,
  1051. PgmSendNcfCompletion, // Completion
  1052. pSend, // Context1
  1053. pNcfPacket, // Context2
  1054. pSend->pSender->DestMCastIpAddress,
  1055. pSend->pSender->DestMCastPort);
  1056. ASSERT (NT_SUCCESS (status));
  1057. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendNcf",
  1058. "Sent <%d> bytes to <%x:%d>\n",
  1059. NakPacketLength, pSend->pSender->DestMCastIpAddress, pSend->pSender->DestMCastPort);
  1060. return (status);
  1061. }
  1062. //----------------------------------------------------------------------------
  1063. NTSTATUS
  1064. FilterAndAddNaksToList(
  1065. IN tSEND_SESSION *pSend,
  1066. IN tNAKS_LIST *pNaksList
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. This routine processes a list of Naks, removing duplicates and adding
  1071. new Naks where necessary
  1072. Arguments:
  1073. IN pSend -- Pgm session (sender) context
  1074. IN pNaksList -- Contains Nak type and List of Nak sequences
  1075. Return Value:
  1076. NTSTATUS - Final status of the call
  1077. --*/
  1078. {
  1079. tSEND_RDATA_CONTEXT *pRDataContext;
  1080. tSEND_RDATA_CONTEXT *pRDataNew;
  1081. LIST_ENTRY *pEntry;
  1082. ULONG i, j, NumNcfs, RDataContextSize;
  1083. ULONGLONG PreRDataWait;
  1084. //
  1085. // First, eliminate the entries that are currently in the handled list!
  1086. //
  1087. i = 0;
  1088. NumNcfs = 0;
  1089. ASSERT (pNaksList->NumSequences);
  1090. pEntry = &pSend->pSender->HandledRDataRequests;
  1091. while ((pEntry = pEntry->Flink) != &pSend->pSender->HandledRDataRequests)
  1092. {
  1093. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  1094. if (pRDataContext->NakType != pNaksList->NakType)
  1095. {
  1096. continue;
  1097. }
  1098. if (pRDataContext->RDataSequenceNumber == pNaksList->pNakSequences[i])
  1099. {
  1100. #if 0
  1101. //
  1102. // If this RData has passed the Linger time, cleanup here!
  1103. //
  1104. if ((pRDataContext->CleanupTime) &&
  1105. (pSend->pSender->TimerTickCount > pRDataContext->CleanupTime))
  1106. {
  1107. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "FilterAndAddNaksToList",
  1108. "Removing lingering RData for SeqNum=<%d>\n", (ULONG) pRDataContext->RDataSequenceNumber);
  1109. pEntry = pEntry->Blink; // Set this because this pEntry will not be valid any more!
  1110. RemoveEntryList (&pRDataContext->Linkage);
  1111. PgmFreeMem (pRDataContext);
  1112. continue;
  1113. }
  1114. #endif // 0
  1115. pSend->pSender->NumNaksAfterRData++;
  1116. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "FilterAndAddNaksToList",
  1117. "Ignoring Sequence # [%d] since we just sent RData for it!\n",
  1118. (ULONG) pNaksList->pNakSequences[i]);
  1119. pNaksList->NumSequences--;
  1120. for (j = i; j < pNaksList->NumSequences; j++)
  1121. {
  1122. pNaksList->pNakSequences[j] = pNaksList->pNakSequences[j+1];
  1123. pNaksList->NumNaks[j] = pNaksList->NumNaks[j+1];
  1124. }
  1125. }
  1126. else if (SEQ_GT (pRDataContext->RDataSequenceNumber, pNaksList->pNakSequences[i]))
  1127. {
  1128. //
  1129. // Our current sequence is not in the list, so go to the next one
  1130. // and recompare with this sequence
  1131. //
  1132. i++;
  1133. pEntry = pEntry->Blink;
  1134. }
  1135. if (i >= pNaksList->NumSequences)
  1136. {
  1137. break;
  1138. }
  1139. }
  1140. //
  1141. // Now, check for pending RData requests and add new ones if necessary
  1142. //
  1143. i = 0;
  1144. RDataContextSize = sizeof(tSEND_RDATA_CONTEXT) + pSend->FECGroupSize*sizeof(PUCHAR);
  1145. pEntry = &pSend->pSender->PendingRDataRequests;
  1146. while ((pEntry = pEntry->Flink) != &pSend->pSender->PendingRDataRequests)
  1147. {
  1148. if (i >= pNaksList->NumSequences)
  1149. {
  1150. break;
  1151. }
  1152. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  1153. if (SEQ_LT (pRDataContext->RDataSequenceNumber, pNaksList->pNakSequences[i]))
  1154. {
  1155. continue;
  1156. }
  1157. if (SEQ_GT (pRDataContext->RDataSequenceNumber, pNaksList->pNakSequences[i]) ||
  1158. ((pRDataContext->NakType == NAK_TYPE_SELECTIVE) && // If seq #s are equal, parity Naks will be added before selective
  1159. (pNaksList->NakType == NAK_TYPE_PARITY)))
  1160. {
  1161. //
  1162. // Our current sequence is not in the list, so add it!
  1163. //
  1164. if (!(pRDataNew = PgmAllocMem (RDataContextSize, PGM_TAG('2'))))
  1165. {
  1166. PgmLog (PGM_LOG_ERROR, DBG_SEND, "FilterAndAddNaksToList",
  1167. "[1] STATUS_INSUFFICIENT_RESOURCES\n");
  1168. return (STATUS_INSUFFICIENT_RESOURCES);
  1169. }
  1170. PgmZeroMemory (pRDataNew, RDataContextSize);
  1171. pRDataNew->Linkage.Flink = pEntry;
  1172. pRDataNew->Linkage.Blink = pEntry->Blink;
  1173. pEntry->Blink->Flink = &pRDataNew->Linkage;
  1174. pEntry->Blink = &pRDataNew->Linkage;
  1175. pRDataNew->pSend = pSend;
  1176. pRDataNew->RDataSequenceNumber = pNaksList->pNakSequences[i];
  1177. pRDataNew->NakType = pNaksList->NakType;
  1178. pRDataNew->NumNaks = pNaksList->NumNaks[i];
  1179. pRDataNew->RequestTime = pSend->pSender->CurrentTimeoutCount;
  1180. pSend->pSender->NumOutstandingNaks += pNaksList->NumNaks[i];
  1181. pSend->pSender->NumRDataRequestsPending++;
  1182. if (SEQ_GT (pSend->pSender->LastODataSentSequenceNumber, pSend->pSender->TrailingGroupSequenceNumber))
  1183. {
  1184. PreRDataWait = (((SEQ_TYPE) (pRDataNew->RDataSequenceNumber -
  1185. pSend->pSender->TrailingGroupSequenceNumber)) *
  1186. pSend->pSender->RDataLingerTime) /
  1187. ((SEQ_TYPE) (pSend->pSender->LastODataSentSequenceNumber -
  1188. pSend->pSender->TrailingGroupSequenceNumber + 1));
  1189. ASSERT (PreRDataWait <= RDATA_LINGER_TIME_MSECS / BASIC_TIMER_GRANULARITY_IN_MSECS);
  1190. pRDataNew->EarliestRDataSendTime = pSend->pSender->TimerTickCount + PreRDataWait;
  1191. pRDataNew->PostRDataHoldTime = pSend->pSender->RDataLingerTime - PreRDataWait;
  1192. }
  1193. else
  1194. {
  1195. pRDataNew->EarliestRDataSendTime = 0;
  1196. pRDataNew->PostRDataHoldTime = pSend->pSender->RDataLingerTime;
  1197. }
  1198. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "FilterAndAddNaksToList",
  1199. "Inserted Sequence # [%d] to RData list!\n",
  1200. (ULONG) pNaksList->pNakSequences[i]);
  1201. pEntry = &pRDataNew->Linkage;
  1202. }
  1203. //
  1204. // (pRDataContext->RDataSequenceNumber == pNaksList->pNakSequences[i])
  1205. //
  1206. else if (pRDataContext->NakType != pNaksList->NakType) // RData is Parity and Nak is Selective, so check next entry
  1207. {
  1208. continue;
  1209. }
  1210. else
  1211. {
  1212. if (pNaksList->NumNaks[i] > pRDataContext->NumNaks)
  1213. {
  1214. pSend->pSender->NumOutstandingNaks += (pNaksList->NumNaks[i] - pRDataContext->NumNaks);
  1215. pRDataContext->NumNaks = pNaksList->NumNaks[i];
  1216. }
  1217. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "FilterAndAddNaksToList",
  1218. "Ignoring Sequence # [%d] since we just already have pending RData!\n",
  1219. (ULONG) pNaksList->pNakSequences[i]);
  1220. }
  1221. i++;
  1222. }
  1223. //
  1224. // Now, add any remaining Nak entries at the end of the Pending list
  1225. //
  1226. for ( ; i < pNaksList->NumSequences; i++)
  1227. {
  1228. //
  1229. // Add this sequence number to the end of the list
  1230. //
  1231. if (!(pRDataNew = PgmAllocMem (RDataContextSize, PGM_TAG('2'))))
  1232. {
  1233. PgmLog (PGM_LOG_ERROR, DBG_SEND, "FilterAndAddNaksToList",
  1234. "[2] STATUS_INSUFFICIENT_RESOURCES\n");
  1235. return (STATUS_DATA_NOT_ACCEPTED);
  1236. }
  1237. PgmZeroMemory (pRDataNew, RDataContextSize);
  1238. pRDataNew->pSend = pSend;
  1239. pRDataNew->RDataSequenceNumber = pNaksList->pNakSequences[i];
  1240. pRDataNew->NakType = pNaksList->NakType;
  1241. pRDataNew->NumNaks = pNaksList->NumNaks[i];
  1242. pRDataNew->RequestTime = pSend->pSender->CurrentTimeoutCount;
  1243. InsertTailList (&pSend->pSender->PendingRDataRequests, &pRDataNew->Linkage);
  1244. pSend->pSender->NumOutstandingNaks += pNaksList->NumNaks[i];
  1245. pSend->pSender->NumRDataRequestsPending++;
  1246. if (SEQ_GT (pSend->pSender->LastODataSentSequenceNumber, pSend->pSender->TrailingGroupSequenceNumber))
  1247. {
  1248. PreRDataWait = (((SEQ_TYPE) (pRDataNew->RDataSequenceNumber -
  1249. pSend->pSender->TrailingGroupSequenceNumber)) *
  1250. pSend->pSender->RDataLingerTime) /
  1251. ((SEQ_TYPE) (pSend->pSender->LastODataSentSequenceNumber -
  1252. pSend->pSender->TrailingGroupSequenceNumber + 1));
  1253. pRDataNew->EarliestRDataSendTime = pSend->pSender->TimerTickCount + PreRDataWait;
  1254. pRDataNew->PostRDataHoldTime = pSend->pSender->RDataLingerTime - PreRDataWait;
  1255. }
  1256. else
  1257. {
  1258. pRDataNew->EarliestRDataSendTime = 0;
  1259. pRDataNew->PostRDataHoldTime = pSend->pSender->RDataLingerTime;
  1260. }
  1261. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "FilterAndAddNaksToList",
  1262. "Appended Sequence # [%d] to RData list!\n",
  1263. (ULONG) pNaksList->pNakSequences[i]);
  1264. }
  1265. return (STATUS_SUCCESS);
  1266. }
  1267. //----------------------------------------------------------------------------
  1268. NTSTATUS
  1269. SenderProcessNakPacket(
  1270. IN tADDRESS_CONTEXT *pAddress,
  1271. IN tSEND_SESSION *pSend,
  1272. IN ULONG PacketLength,
  1273. IN tBASIC_NAK_NCF_PACKET_HEADER UNALIGNED *pNakPacket
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This routine processes an incoming Nak packet sent to the sender
  1278. Arguments:
  1279. IN pAddress -- Pgm's address object
  1280. IN pSend -- Pgm session (sender) context
  1281. IN PacketLength -- Nak packet length
  1282. IN pNakPacket -- Nak packet data
  1283. Return Value:
  1284. NTSTATUS - Final status of the call
  1285. --*/
  1286. {
  1287. PGMLockHandle OldIrq;
  1288. tNAKS_LIST NaksList;
  1289. tSEND_RDATA_CONTEXT *pRDataContext;
  1290. tSEND_RDATA_CONTEXT *pRDataNew;
  1291. SEQ_TYPE LastSequenceNumber;
  1292. NTSTATUS status;
  1293. if (PacketLength < sizeof(tBASIC_NAK_NCF_PACKET_HEADER))
  1294. {
  1295. PgmLog (PGM_LOG_ERROR, DBG_SEND, "SenderProcessNakPacket",
  1296. "Invalid Packet length=<%d>, Min=<%d> ...\n",
  1297. PacketLength, sizeof(tBASIC_NAK_NCF_PACKET_HEADER));
  1298. return (STATUS_DATA_NOT_ACCEPTED);
  1299. }
  1300. ASSERT (!pNakPacket->CommonHeader.TSDULength);
  1301. PgmLock (pSend, OldIrq);
  1302. status = ExtractNakNcfSequences (pNakPacket,
  1303. (PacketLength - sizeof(tBASIC_NAK_NCF_PACKET_HEADER)),
  1304. &NaksList,
  1305. pSend->FECGroupSize);
  1306. if (!NT_SUCCESS (status))
  1307. {
  1308. PgmUnlock (pSend, OldIrq);
  1309. PgmLog (PGM_LOG_ERROR, DBG_SEND, "SenderProcessNakPacket",
  1310. "ExtractNakNcfSequences returned <%x>\n", status);
  1311. return (status);
  1312. }
  1313. pSend->pSender->NaksReceived += NaksList.NumSequences;
  1314. //
  1315. // The oldest as well as latest sequence numbers have to be in our window
  1316. //
  1317. if (SEQ_LT (NaksList.pNakSequences[0], pSend->pSender->TrailingGroupSequenceNumber) ||
  1318. SEQ_GT (NaksList.pNakSequences[NaksList.NumSequences-1], pSend->pSender->LastODataSentSequenceNumber))
  1319. {
  1320. pSend->pSender->NaksReceivedTooLate++;
  1321. PgmUnlock (pSend, OldIrq);
  1322. PgmLog (PGM_LOG_ERROR, DBG_SEND, "SenderProcessNakPacket",
  1323. "Invalid %s Naks = [%d-%d] not in window [%d -- [%d]\n",
  1324. (NaksList.NakType == NAK_TYPE_PARITY ? "Parity" : "Selective"),
  1325. (ULONG) NaksList.pNakSequences[0], (ULONG) NaksList.pNakSequences[NaksList.NumSequences-1],
  1326. (ULONG) pSend->pSender->TrailingGroupSequenceNumber, (ULONG) pSend->pSender->LastODataSentSequenceNumber);
  1327. return (STATUS_DATA_NOT_ACCEPTED);
  1328. }
  1329. //
  1330. // Check if this is a parity Nak and we are anabled for Parity Naks
  1331. //
  1332. if ((pNakPacket->CommonHeader.Options & PACKET_HEADER_OPTIONS_PARITY) &&
  1333. !(pSend->FECOptions & PACKET_OPTION_SPECIFIC_FEC_OND_BIT))
  1334. {
  1335. PgmLog (PGM_LOG_ERROR, DBG_SEND, "SenderProcessNakPacket",
  1336. "Receiver requested Parity Naks, but we are not enabled for parity!\n");
  1337. PgmUnlock (pSend, OldIrq);
  1338. return (STATUS_DATA_NOT_ACCEPTED);
  1339. }
  1340. status = FilterAndAddNaksToList (pSend, &NaksList);
  1341. PgmUnlock (pSend, OldIrq);
  1342. if (!NT_SUCCESS (status))
  1343. {
  1344. PgmLog (PGM_LOG_ERROR, DBG_SEND, "SenderProcessNakPacket",
  1345. "FilterAndAddNaksToList returned <%x>\n", status);
  1346. return (status);
  1347. }
  1348. //
  1349. // If applicable, send the Ncf for this Nak
  1350. //
  1351. if (NaksList.NumSequences)
  1352. {
  1353. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "SenderProcessNakPacket",
  1354. "Now sending Ncf for Nak received for <%d> Sequences, NakType=<%x>\n",
  1355. NaksList.NumSequences, NaksList.NakType);
  1356. status = PgmSendNcf (pSend, pNakPacket, &NaksList, PacketLength);
  1357. }
  1358. return (STATUS_SUCCESS);
  1359. }
  1360. //----------------------------------------------------------------------------
  1361. NTSTATUS
  1362. PgmSetFin(
  1363. IN tSEND_SESSION *pSend,
  1364. IN tCLIENT_SEND_REQUEST *pSendContext,
  1365. IN PGMLockHandle *pOldIrq
  1366. )
  1367. /*++
  1368. Routine Description:
  1369. This routine is called to set the Fin option on the last data packet
  1370. if the packets have been packetized, but not yet sent out
  1371. The pSend lock is held before calling this routine
  1372. Arguments:
  1373. IN pSend -- Pgm session (sender) context
  1374. IN pOldIrq -- pSend's OldIrq
  1375. Return Value:
  1376. NTSTATUS - Final status of the set FIN operation
  1377. --*/
  1378. {
  1379. KAPC_STATE ApcState;
  1380. BOOLEAN fAttached;
  1381. NTSTATUS status;
  1382. tPACKET_BUFFER *pPacketBuffer;
  1383. ULONG OptionsFlags;
  1384. ULONGLONG LastPacketOffset;
  1385. tBASIC_DATA_PACKET_HEADER *pLastDataPacket;
  1386. tBASIC_DATA_PACKET_HEADER *pFinPacket = NULL;
  1387. SEQ_TYPE LastODataSequenceNumber = pSend->pSender->NextODataSequenceNumber - 1;
  1388. USHORT OriginalHeaderLength, HeaderLength = (USHORT) pSend->pSender->PacketBufferSize;
  1389. //
  1390. // This will be called only if we have finished packetizing
  1391. // all the packets, but have not yet sent the last one out!
  1392. // We need to set the FIN on the last packet
  1393. //
  1394. ASSERT (!pSendContext->BytesLeftToPacketize);
  1395. ASSERT (pSendContext->pIrp);
  1396. //
  1397. // First set the FIN flag so that the Spm can get sent
  1398. //
  1399. pSendContext->DataOptions |= PGM_OPTION_FLAG_FIN;
  1400. //
  1401. // Allocate memory for saving the last packet's data
  1402. //
  1403. if (!(pFinPacket = PgmAllocMem (pSend->pSender->PacketBufferSize, PGM_TAG('2'))))
  1404. {
  1405. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSetFin",
  1406. "STATUS_INSUFFICIENT_RESOURCES\n");
  1407. return (STATUS_INSUFFICIENT_RESOURCES);
  1408. }
  1409. //
  1410. // First, determine where the last packet packetized is located
  1411. //
  1412. if (pSend->pSender->LeadingWindowOffset < pSend->pSender->PacketBufferSize)
  1413. {
  1414. ASSERT (pSend->pSender->LeadingWindowOffset == 0); // This is the only valid value!
  1415. LastPacketOffset = pSend->pSender->MaxDataFileSize - pSend->pSender->PacketBufferSize;
  1416. }
  1417. else
  1418. {
  1419. ASSERT (pSend->pSender->LeadingWindowOffset < pSend->pSender->MaxDataFileSize);
  1420. LastPacketOffset = pSend->pSender->LeadingWindowOffset - pSend->pSender->PacketBufferSize;
  1421. }
  1422. pPacketBuffer = (tPACKET_BUFFER *) (((PUCHAR) pSend->pSender->SendDataBufferMapping) + LastPacketOffset);
  1423. pLastDataPacket = &pPacketBuffer->DataPacket;
  1424. //
  1425. // First get all the options that were set in the last packet
  1426. //
  1427. PgmUnlock (pSend, *pOldIrq);
  1428. PgmAttachToProcessForVMAccess (pSend->Process, &ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  1429. OptionsFlags = pPacketBuffer->PacketOptions.OptionsFlags | PGM_OPTION_FLAG_FIN;
  1430. OriginalHeaderLength = sizeof(tBASIC_DATA_PACKET_HEADER) + pPacketBuffer->PacketOptions.OptionsLength;
  1431. PgmZeroMemory (pFinPacket, pSend->pSender->PacketBufferSize);
  1432. status = InitDataSpmHeader (pSend,
  1433. pSendContext,
  1434. (PUCHAR) pFinPacket,
  1435. &HeaderLength,
  1436. OptionsFlags,
  1437. &pPacketBuffer->PacketOptions,
  1438. PACKET_TYPE_ODATA);
  1439. if (!NT_SUCCESS (status))
  1440. {
  1441. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSetFin",
  1442. "[1] InitDataSpmHeader returned <%x>\n", status);
  1443. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  1444. PgmLock (pSend, *pOldIrq);
  1445. PgmFreeMem (pFinPacket);
  1446. return (status);
  1447. }
  1448. pFinPacket->DataSequenceNumber = htonl ((ULONG) LastODataSequenceNumber);
  1449. pFinPacket->CommonHeader.TSDULength = htons (pPacketBuffer->PacketOptions.TotalPacketLength -
  1450. OriginalHeaderLength);
  1451. ASSERT (pFinPacket->DataSequenceNumber == pLastDataPacket->DataSequenceNumber);
  1452. //
  1453. // Copy the data
  1454. //
  1455. PgmCopyMemory (&((PUCHAR) pFinPacket) [HeaderLength],
  1456. &((PUCHAR) pLastDataPacket) [OriginalHeaderLength],
  1457. (pSend->pSender->MaxPayloadSize));
  1458. //
  1459. // Now, copy the reconstructed packet back into the buffer
  1460. //
  1461. if (pSend->FECOptions)
  1462. {
  1463. PgmCopyMemory (&((PUCHAR)pFinPacket) [HeaderLength + pSend->pSender->MaxPayloadSize],
  1464. &((PUCHAR)pLastDataPacket) [OriginalHeaderLength + pSend->pSender->MaxPayloadSize],
  1465. sizeof(tPOST_PACKET_FEC_CONTEXT));
  1466. PgmCopyMemory (pLastDataPacket, pFinPacket,
  1467. (HeaderLength+pSend->pSender->MaxPayloadSize+sizeof(tPOST_PACKET_FEC_CONTEXT)));
  1468. }
  1469. else
  1470. {
  1471. PgmCopyMemory (pLastDataPacket, pFinPacket, (HeaderLength+pSend->pSender->MaxPayloadSize));
  1472. }
  1473. pPacketBuffer->PacketOptions.TotalPacketLength = HeaderLength +
  1474. ntohs (pFinPacket->CommonHeader.TSDULength);
  1475. pPacketBuffer->PacketOptions.OptionsFlags = OptionsFlags;
  1476. pPacketBuffer->PacketOptions.OptionsLength = HeaderLength - sizeof(tBASIC_DATA_PACKET_HEADER);
  1477. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  1478. PgmLock (pSend, *pOldIrq);
  1479. PgmFreeMem (pFinPacket);
  1480. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSetFin",
  1481. "Set Fin option on last packet\n");
  1482. return (STATUS_SUCCESS);
  1483. }
  1484. //----------------------------------------------------------------------------
  1485. NTSTATUS
  1486. PacketizeMessage(
  1487. IN tSEND_SESSION *pSend,
  1488. IN PGMLockHandle *pOldIrq,
  1489. IN tCLIENT_SEND_REQUEST *pSendContext,
  1490. IN OUT ULONG *pBytesToPacketize,
  1491. IN OUT ULONGLONG *pLeadingWindowOffset,
  1492. IN ULONGLONG *pTrailingWindowOffset,
  1493. IN OUT ULONGLONG *pBufferSize,
  1494. IN OUT SEQ_TYPE *pNextODataSequenceNumber,
  1495. IN OUT ULONG *pBytesPacketized,
  1496. IN OUT ULONG *pNextDataOffsetInMdl,
  1497. IN OUT ULONG *pDataPacketsPacketized,
  1498. IN OUT ULONG *pDataBytesInLastPacket,
  1499. OUT PVOID *ppLastVariableTGPacket
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. This routine pactizes the data to be sent into packets
  1504. The pSend lock is held before calling this routine
  1505. Arguments:
  1506. IN pSend -- Pgm session (sender) context
  1507. IN pOldIrq -- pSend's OldIrq
  1508. IN pSendContext -- Pgm's SendContext for this send request from client
  1509. IN OUT pBytesToPacketize -- Client data bytes left to packetize before and after
  1510. IN OUT pLeadingWindowOffset
  1511. IN OUT pBufferSizeAvailable -- IN ==> Buffer available, OUT ==> Buffer consumed
  1512. IN OUT pBytesPacketized
  1513. IN OUT pDataPacketsPacketized
  1514. IN OUT pDataBytesInLastPacket
  1515. Return Value:
  1516. NTSTATUS - Final status of the request
  1517. --*/
  1518. {
  1519. tBASIC_DATA_PACKET_HEADER *pODataBuffer;
  1520. ULONG ulBytes, DataOptions;
  1521. USHORT usBytes, HeaderLength, PacketsLeftInGroup;
  1522. KAPC_STATE ApcState;
  1523. BOOLEAN fAttached;
  1524. tPACKET_OPTIONS *pPacketOptions;
  1525. tPACKET_BUFFER *pPacketBuffer;
  1526. tPACKET_BUFFER *pGroupLeaderPacketBuffer;
  1527. tPOST_PACKET_FEC_CONTEXT UNALIGNED *pBufferFECContext;
  1528. tPOST_PACKET_FEC_CONTEXT FECContext;
  1529. ULONGLONG Buffer1Packets, Buffer2Packets;
  1530. ULONGLONG ActualBuffer1Packets, ActualBuffer2Packets;
  1531. SEQ_TYPE FECGroupMask = pSend->FECGroupSize-1;
  1532. ULONG NumPacketsRemaining;
  1533. tSEND_CONTEXT *pSender = pSend->pSender;
  1534. NTSTATUS status = STATUS_SUCCESS;
  1535. PMDL pMdlChain = pSendContext->pIrp->MdlAddress;
  1536. ULONG BytesToPacketize = *pBytesToPacketize;
  1537. ULONGLONG LeadingWindowOffset = *pLeadingWindowOffset;
  1538. ULONGLONG TrailingWindowOffset = *pTrailingWindowOffset;
  1539. ULONGLONG BufferSizeAvailable = *pBufferSize;
  1540. SEQ_TYPE NextODataSequenceNumber = *pNextODataSequenceNumber;
  1541. ULONG BytesPacketized = *pBytesPacketized;
  1542. ULONG NextDataOffsetInMdl = *pNextDataOffsetInMdl;
  1543. ULONG DataPacketsPacketized = *pDataPacketsPacketized;
  1544. ULONG DataBytesInLastPacket = *pDataBytesInLastPacket;
  1545. //
  1546. // First do some sanity checks!
  1547. //
  1548. ASSERT (LeadingWindowOffset < pSender->MaxDataFileSize);
  1549. ASSERT (BufferSizeAvailable <= pSender->MaxDataFileSize);
  1550. ASSERT (pSend->FECGroupSize);
  1551. //
  1552. // Next, determine how many Packets we can packetize at this time
  1553. // For FEC, we will need to make sure we don't packetize beyond
  1554. // the first group of the trailing edge!
  1555. // We will do 2 sets of calculations -- ActualBuffer[n]Packets represents
  1556. // the actual number of available packets, while Buffer[n]Packets
  1557. // represents the packets available for packetization
  1558. //
  1559. if (!BufferSizeAvailable)
  1560. {
  1561. //
  1562. // Our buffer is full!
  1563. //
  1564. Buffer1Packets = Buffer2Packets = 0;
  1565. ActualBuffer1Packets = ActualBuffer2Packets = 0;
  1566. ASSERT (LeadingWindowOffset == TrailingWindowOffset);
  1567. }
  1568. else if (LeadingWindowOffset < TrailingWindowOffset)
  1569. {
  1570. #if DBG
  1571. // ActualBuffer1Packets = (TrailingWindowOffset - LeadingWindowOffset) / pSender->PacketBufferSize;
  1572. ActualBuffer1Packets = TrailingWindowOffset / pSender->PacketBufferSize;
  1573. ActualBuffer2Packets = LeadingWindowOffset / pSender->PacketBufferSize;
  1574. Buffer1Packets = ActualBuffer1Packets & ~((ULONGLONG) FECGroupMask);
  1575. ActualBuffer1Packets -= ActualBuffer2Packets;
  1576. Buffer1Packets -= ActualBuffer2Packets;
  1577. #else
  1578. Buffer1Packets = (TrailingWindowOffset / pSender->PacketBufferSize) & ~((ULONGLONG)FECGroupMask);
  1579. Buffer1Packets -= LeadingWindowOffset / pSender->PacketBufferSize;
  1580. #endif // DBG
  1581. ActualBuffer2Packets = Buffer2Packets = 0;
  1582. }
  1583. else
  1584. {
  1585. ActualBuffer1Packets = Buffer1Packets = (pSender->MaxDataFileSize - LeadingWindowOffset) /
  1586. pSender->PacketBufferSize;
  1587. #if DBG
  1588. ActualBuffer2Packets = TrailingWindowOffset / pSender->PacketBufferSize;
  1589. Buffer2Packets = ActualBuffer2Packets & ~((ULONGLONG)FECGroupMask);
  1590. #else
  1591. Buffer2Packets = (TrailingWindowOffset / pSender->PacketBufferSize) & ~((ULONGLONG)FECGroupMask);
  1592. #endif // DBG
  1593. }
  1594. ASSERT (Buffer1Packets || !Buffer2Packets);
  1595. ASSERT (((ActualBuffer1Packets + ActualBuffer2Packets) *
  1596. pSender->PacketBufferSize) == BufferSizeAvailable);
  1597. ASSERT (Buffer1Packets <= ActualBuffer1Packets);
  1598. ASSERT (Buffer2Packets <= ActualBuffer2Packets);
  1599. // Initialize
  1600. NumPacketsRemaining = pSender->NumPacketsRemaining;
  1601. PacketsLeftInGroup = pSend->FECGroupSize - (UCHAR) (NextODataSequenceNumber & FECGroupMask);
  1602. if (pSend->FECOptions)
  1603. {
  1604. PgmZeroMemory (&FECContext, sizeof (tPOST_PACKET_FEC_CONTEXT));
  1605. }
  1606. PgmUnlock (pSend, *pOldIrq);
  1607. PgmAttachToProcessForVMAccess (pSend->Process, &ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  1608. while (Buffer1Packets || Buffer2Packets)
  1609. {
  1610. //
  1611. // For FEC, we must start the next send from the next group boundary.
  1612. // Thus, we need to pad any intermediate sequence# packets
  1613. //
  1614. if (!BytesToPacketize)
  1615. {
  1616. if ((NumPacketsRemaining >= 1) || // More packets, so not a partial group
  1617. (PacketsLeftInGroup == pSend->FECGroupSize)) // New group boundary (always TRUE for non-FEC packets!)
  1618. {
  1619. break;
  1620. }
  1621. }
  1622. //
  1623. // Get the next packet ptr and Packet size
  1624. //
  1625. pPacketBuffer = (tPACKET_BUFFER *) (pSender->SendDataBufferMapping + LeadingWindowOffset);
  1626. pODataBuffer = &pPacketBuffer->DataPacket;
  1627. pPacketOptions = &pPacketBuffer->PacketOptions;
  1628. PgmZeroMemory (pPacketBuffer, pSender->PacketBufferSize); // Zero the entire buffer
  1629. //
  1630. // Prepare info for any applicable options
  1631. //
  1632. pPacketOptions->OptionsFlags = pSendContext->DataOptions;
  1633. ulBytes = pSendContext->DataOptionsLength; // Save for assert below
  1634. if ((BytesToPacketize) &&
  1635. (pPacketOptions->OptionsFlags & PGM_OPTION_FLAG_FRAGMENT))
  1636. {
  1637. pPacketOptions->MessageFirstSequence = (ULONG) (SEQ_TYPE) pSendContext->MessageFirstSequenceNumber;
  1638. pPacketOptions->MessageOffset = pSendContext->LastMessageOffset + BytesPacketized;
  1639. pPacketOptions->MessageLength = pSendContext->ThisMessageLength;
  1640. }
  1641. else
  1642. {
  1643. if (pPacketOptions->OptionsFlags & PGM_OPTION_FLAG_FRAGMENT)
  1644. {
  1645. ASSERT (!BytesToPacketize);
  1646. pPacketOptions->OptionsFlags &= ~PGM_OPTION_FLAG_FRAGMENT;
  1647. if (pPacketOptions->OptionsFlags)
  1648. {
  1649. ulBytes -= PGM_PACKET_OPT_FRAGMENT_LENGTH;
  1650. }
  1651. else
  1652. {
  1653. ulBytes = 0;
  1654. }
  1655. }
  1656. }
  1657. if (pPacketOptions->OptionsFlags & PGM_OPTION_FLAG_JOIN)
  1658. {
  1659. //
  1660. // See if we have enough packets for the LateJoiner sequence numbers
  1661. //
  1662. if (SEQ_GT (NextODataSequenceNumber, (pSender->TrailingGroupSequenceNumber +
  1663. pSender->LateJoinSequenceNumbers)))
  1664. {
  1665. pPacketOptions->LateJoinerSequence = (ULONG) (SEQ_TYPE) (NextODataSequenceNumber -
  1666. pSender->LateJoinSequenceNumbers);
  1667. }
  1668. else
  1669. {
  1670. pPacketOptions->LateJoinerSequence = (ULONG) (SEQ_TYPE) pSender->TrailingGroupSequenceNumber;
  1671. }
  1672. }
  1673. if (pSend->FECBlockSize) // Check if this is FEC-enabled
  1674. {
  1675. //
  1676. // Save information if we are at beginning of group boundary
  1677. //
  1678. if (PacketsLeftInGroup == pSend->FECGroupSize)
  1679. {
  1680. pPacketOptions->FECContext.SenderNextFECPacketIndex = pSend->FECGroupSize;
  1681. }
  1682. //
  1683. // Check if we need to set the variable TG size option
  1684. //
  1685. if ((NumPacketsRemaining == 1) && // Last packet
  1686. (BytesToPacketize) && // non-Zero length
  1687. (PacketsLeftInGroup > 1)) // Variable TG size
  1688. {
  1689. //
  1690. // This is a variable Transmission Group Size, i.e. PacketsInGroup < pSend->FECGroupSize
  1691. //
  1692. ASSERT ((Buffer1Packets + Buffer2Packets) >= PacketsLeftInGroup);
  1693. if (!pPacketOptions->OptionsFlags)
  1694. {
  1695. ulBytes = PGM_PACKET_EXTENSION_LENGTH;
  1696. }
  1697. ulBytes += PGM_PACKET_OPT_PARITY_CUR_TGSIZE_LENGTH;
  1698. pPacketOptions->OptionsFlags |= PGM_OPTION_FLAG_PARITY_CUR_TGSIZE;
  1699. pPacketOptions->FECContext.NumPacketsInThisGroup = pSend->FECGroupSize - (PacketsLeftInGroup - 1);
  1700. *ppLastVariableTGPacket = (PVOID) pODataBuffer;
  1701. }
  1702. }
  1703. HeaderLength = (USHORT) pSender->MaxPayloadSize; // Init -- max buffer size available
  1704. status = InitDataSpmHeader (pSend,
  1705. pSendContext,
  1706. (PUCHAR) pODataBuffer,
  1707. &HeaderLength,
  1708. pPacketOptions->OptionsFlags,
  1709. pPacketOptions,
  1710. PACKET_TYPE_ODATA);
  1711. if (NT_SUCCESS (status))
  1712. {
  1713. ASSERT ((sizeof(tBASIC_DATA_PACKET_HEADER) + ulBytes) == HeaderLength);
  1714. ASSERT ((pSend->FECBlockSize && (HeaderLength+pSendContext->DataPayloadSize) <=
  1715. (pSender->PacketBufferSize-sizeof(tPOST_PACKET_FEC_CONTEXT))) ||
  1716. (!pSend->FECBlockSize && ((HeaderLength+pSendContext->DataPayloadSize) <=
  1717. pSender->PacketBufferSize)));
  1718. if (BytesToPacketize > pSender->MaxPayloadSize)
  1719. {
  1720. DataBytesInLastPacket = pSender->MaxPayloadSize;
  1721. }
  1722. else
  1723. {
  1724. DataBytesInLastPacket = (USHORT) BytesToPacketize;
  1725. }
  1726. pODataBuffer->CommonHeader.TSDULength = htons ((USHORT) DataBytesInLastPacket);
  1727. pODataBuffer->DataSequenceNumber = htonl ((ULONG) NextODataSequenceNumber++);
  1728. ulBytes = 0;
  1729. status = TdiCopyMdlToBuffer (pMdlChain,
  1730. NextDataOffsetInMdl,
  1731. (((PUCHAR) pODataBuffer) + HeaderLength),
  1732. 0, // Destination Offset
  1733. DataBytesInLastPacket,
  1734. &ulBytes);
  1735. if (((!NT_SUCCESS (status)) && (STATUS_BUFFER_OVERFLOW != status)) || // Overflow acceptable!
  1736. (ulBytes != DataBytesInLastPacket))
  1737. {
  1738. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PacketizeMessage",
  1739. "TdiCopyMdlToBuffer returned <%x>, BytesCopied=<%d/%d>\n",
  1740. status, ulBytes, DataBytesInLastPacket);
  1741. status = STATUS_UNSUCCESSFUL;
  1742. }
  1743. else
  1744. {
  1745. pPacketOptions->TotalPacketLength = HeaderLength + (USHORT) DataBytesInLastPacket;
  1746. pPacketOptions->OptionsLength = HeaderLength - sizeof (tBASIC_DATA_PACKET_HEADER);
  1747. //
  1748. // Set the PacketOptions Information for FEC packets
  1749. //
  1750. if (pSend->FECOptions)
  1751. {
  1752. pBufferFECContext = (tPOST_PACKET_FEC_CONTEXT *) (((PUCHAR) pODataBuffer) +
  1753. HeaderLength +
  1754. pSender->MaxPayloadSize);
  1755. if (DataBytesInLastPacket)
  1756. {
  1757. FECContext.EncodedTSDULength = htons ((USHORT) DataBytesInLastPacket);
  1758. FECContext.EncodedFragmentOptions.MessageFirstSequence = htonl ((ULONG) (SEQ_TYPE) pPacketOptions->MessageFirstSequence);
  1759. FECContext.EncodedFragmentOptions.MessageOffset = htonl (pPacketOptions->MessageOffset);
  1760. FECContext.EncodedFragmentOptions.MessageLength = htonl (pPacketOptions->MessageLength);
  1761. PgmCopyMemory (pBufferFECContext, &FECContext, sizeof (tPOST_PACKET_FEC_CONTEXT));
  1762. }
  1763. else
  1764. {
  1765. //
  1766. // We had already initialized this memory earlier in the loop
  1767. //
  1768. // PgmZeroMemory (pBufferFECContext, sizeof (tPOST_PACKET_FEC_CONTEXT));
  1769. }
  1770. //
  1771. // If this is not a fragment, set the PACKET_OPTION_SPECIFIC_ENCODED_NULL_BIT
  1772. //
  1773. if ((!DataBytesInLastPacket) ||
  1774. (!(pPacketOptions->OptionsFlags & PGM_OPTION_FLAG_FRAGMENT)))
  1775. {
  1776. ((PUCHAR) pBufferFECContext)
  1777. [FIELD_OFFSET (tPOST_PACKET_FEC_CONTEXT, FragmentOptSpecific)] =
  1778. PACKET_OPTION_SPECIFIC_ENCODED_NULL_BIT;
  1779. }
  1780. }
  1781. status = STATUS_SUCCESS;
  1782. }
  1783. }
  1784. else
  1785. {
  1786. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PacketizeMessage",
  1787. "InitDataSpmHeader returned <%x>\n", status);
  1788. }
  1789. if (!NT_SUCCESS (status))
  1790. {
  1791. break;
  1792. }
  1793. LeadingWindowOffset += pSender->PacketBufferSize;
  1794. BufferSizeAvailable -= pSender->PacketBufferSize;
  1795. BytesPacketized += DataBytesInLastPacket;
  1796. NextDataOffsetInMdl += DataBytesInLastPacket;
  1797. if (DataBytesInLastPacket)
  1798. {
  1799. DataPacketsPacketized++;
  1800. NumPacketsRemaining--;
  1801. }
  1802. //
  1803. // Update the Send buffer information
  1804. //
  1805. if (!Buffer1Packets)
  1806. {
  1807. Buffer2Packets--;
  1808. }
  1809. else if (0 == --Buffer1Packets)
  1810. {
  1811. ASSERT (((Buffer2Packets == 0) && (TrailingWindowOffset != 0)) ||
  1812. (LeadingWindowOffset == pSender->MaxDataFileSize));
  1813. if (LeadingWindowOffset == pSender->MaxDataFileSize)
  1814. {
  1815. LeadingWindowOffset = 0;
  1816. }
  1817. }
  1818. //
  1819. // Update the Send data information
  1820. //
  1821. BytesToPacketize -= DataBytesInLastPacket;
  1822. //
  1823. // See if we are at a group boundary
  1824. //
  1825. if (!--PacketsLeftInGroup)
  1826. {
  1827. PacketsLeftInGroup = pSend->FECGroupSize;
  1828. }
  1829. }
  1830. ASSERT ((Buffer1Packets || Buffer2Packets) ||
  1831. (BufferSizeAvailable < (pSender->PacketBufferSize * pSend->FECGroupSize)));
  1832. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PacketizeMessage",
  1833. "TotalBytesPacketized=<%d/%d>, BytesToP=<%d==>%d>\n",
  1834. BytesPacketized, pSendContext->BytesInSend, *pBytesToPacketize, BytesToPacketize);
  1835. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  1836. PgmLock (pSend, *pOldIrq);
  1837. //
  1838. // Set the state variables
  1839. //
  1840. *pBytesToPacketize = BytesToPacketize;
  1841. *pLeadingWindowOffset = LeadingWindowOffset;
  1842. *pBufferSize = (*pBufferSize - BufferSizeAvailable);
  1843. *pNextODataSequenceNumber = NextODataSequenceNumber;
  1844. *pBytesPacketized = BytesPacketized;
  1845. *pNextDataOffsetInMdl = NextDataOffsetInMdl;
  1846. *pDataPacketsPacketized = DataPacketsPacketized;
  1847. *pDataBytesInLastPacket = DataBytesInLastPacket;
  1848. return (status);
  1849. }
  1850. //----------------------------------------------------------------------------
  1851. NTSTATUS
  1852. PgmPacketizeSend(
  1853. IN tSEND_SESSION *pSend,
  1854. IN tCLIENT_SEND_REQUEST *pSendContext,
  1855. IN PGMLockHandle *pOldIrq
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. This routine is called to prepare the next set of packets
  1860. for sending on the wire
  1861. The pSend lock is held before calling this routine
  1862. Arguments:
  1863. IN pSend -- Pgm session (sender) context
  1864. IN pOldIrq -- pSend's OldIrq
  1865. Return Value:
  1866. NTSTATUS - Final status of the request
  1867. --*/
  1868. {
  1869. ULONG BytesToPacketize = 0;
  1870. ULONGLONG LeadingWindowOffset;
  1871. ULONGLONG TrailingWindowOffset;
  1872. ULONGLONG BufferSize;
  1873. SEQ_TYPE NextODataSequenceNumber;
  1874. PVOID pLastVariableTGPacket;
  1875. ULONG BytesPacketized;
  1876. ULONG NextDataOffsetInMdl;
  1877. ULONG DataPacketsPacketized;
  1878. ULONG DataBytesInLastPacket;
  1879. NTSTATUS status = STATUS_SUCCESS;
  1880. LIST_ENTRY *pEntry;
  1881. if (pSendContext->BytesLeftToPacketize == pSendContext->BytesInSend)
  1882. {
  1883. pSendContext->NextPacketOffset = pSend->pSender->LeadingWindowOffset; // First packet's offset
  1884. pSendContext->StartSequenceNumber = pSend->pSender->NextODataSequenceNumber;
  1885. pSendContext->EndSequenceNumber = pSend->pSender->NextODataSequenceNumber; // temporary
  1886. if (pSendContext->LastMessageOffset)
  1887. {
  1888. pSendContext->MessageFirstSequenceNumber = pSend->pSender->LastMessageFirstSequence;
  1889. }
  1890. else
  1891. {
  1892. pSendContext->MessageFirstSequenceNumber = pSendContext->StartSequenceNumber;
  1893. pSend->pSender->LastMessageFirstSequence = pSendContext->StartSequenceNumber;
  1894. }
  1895. }
  1896. BytesToPacketize = pSendContext->BytesLeftToPacketize;
  1897. //
  1898. // Since we have a wrap around buffer to be copied into, we also need to
  1899. // determine the # of packets that can be copied contiguously
  1900. //
  1901. ASSERT (pSend->pSender->LeadingWindowOffset < pSend->pSender->MaxDataFileSize);
  1902. ASSERT (pSend->pSender->TrailingWindowOffset < pSend->pSender->MaxDataFileSize);
  1903. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmPacketizeSend",
  1904. "TotalBytes=<%d>, BytesToPacketize=<%d>\n",
  1905. pSendContext->BytesInSend, BytesToPacketize);
  1906. LeadingWindowOffset = pSend->pSender->LeadingWindowOffset;
  1907. NextODataSequenceNumber = pSend->pSender->NextODataSequenceNumber;
  1908. BytesPacketized = pSendContext->BytesInSend - pSendContext->BytesLeftToPacketize;
  1909. NextDataOffsetInMdl = pSendContext->NextDataOffsetInMdl;
  1910. DataBytesInLastPacket = pSendContext->DataBytesInLastPacket;
  1911. //
  1912. // Since some packet headers may have different lengths (based on options),
  1913. // we cannot always compute the exact number of packets needed, so will
  1914. // attempt to packetize sequentially keeping the limits in mind
  1915. //
  1916. //
  1917. // First fill in any packets from the first Message
  1918. //
  1919. if (BytesToPacketize)
  1920. {
  1921. pLastVariableTGPacket = (PVOID) -1;
  1922. DataPacketsPacketized = 0;
  1923. BufferSize = pSend->pSender->BufferSizeAvailable;
  1924. TrailingWindowOffset = pSend->pSender->TrailingWindowOffset;
  1925. status = PacketizeMessage (pSend,
  1926. pOldIrq,
  1927. pSendContext,
  1928. &BytesToPacketize,
  1929. &LeadingWindowOffset,
  1930. &TrailingWindowOffset,
  1931. &BufferSize,
  1932. &NextODataSequenceNumber,
  1933. &BytesPacketized,
  1934. &NextDataOffsetInMdl,
  1935. &DataPacketsPacketized,
  1936. &DataBytesInLastPacket,
  1937. &pLastVariableTGPacket);
  1938. if (NT_SUCCESS (status))
  1939. {
  1940. //
  1941. // Save all the state information
  1942. //
  1943. pSend->pSender->LeadingWindowOffset = LeadingWindowOffset;
  1944. pSend->pSender->BufferSizeAvailable -= BufferSize;
  1945. pSend->pSender->NumPacketsRemaining -= DataPacketsPacketized;
  1946. pSend->pSender->NextODataSequenceNumber = NextODataSequenceNumber;
  1947. pSendContext->BytesLeftToPacketize = pSendContext->BytesInSend - BytesPacketized;
  1948. pSendContext->NextDataOffsetInMdl = NextDataOffsetInMdl;
  1949. pSendContext->DataBytesInLastPacket = DataBytesInLastPacket;
  1950. pSendContext->DataPacketsPacketized += DataPacketsPacketized;
  1951. pSendContext->NumPacketsRemaining -= DataPacketsPacketized;
  1952. if (BytesToPacketize)
  1953. {
  1954. //
  1955. // We must have run out of Buffer space to copy the entire
  1956. // message, which is not an error -- so just return gracefully
  1957. //
  1958. pSendContext->EndSequenceNumber = pSend->pSender->NextODataSequenceNumber - 1;
  1959. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmPacketizeSend",
  1960. "PacketizeMessage[1] SUCCEEDed, but BytesToPacketize=<%d>\n", BytesToPacketize);
  1961. return (STATUS_SUCCESS);
  1962. }
  1963. pSendContext->pLastMessageVariableTGPacket = pLastVariableTGPacket;
  1964. }
  1965. else
  1966. {
  1967. //
  1968. // The function will ensure that Buffer1Packets != 0 on error
  1969. //
  1970. ASSERT (BytesToPacketize);
  1971. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmPacketizeSend",
  1972. "PacketizeMessage[1] returned <%x>\n", status);
  1973. }
  1974. }
  1975. if (!NT_SUCCESS (status))
  1976. {
  1977. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmPacketizeSend",
  1978. "status=<%x>, pSend=<%p>, pSendContext=<%p>, pIrp=<%p>\n",
  1979. status, pSend, pSendContext, pSendContext->pIrp);
  1980. //
  1981. // Mark the remainder of this send as invalid!
  1982. //
  1983. pSendContext->BytesLeftToPacketize = 0;
  1984. // pSend->pSender->SpmOptions |= PGM_OPTION_FLAG_RST; // ISSUE: Do we set this here ?
  1985. //
  1986. // We failed to packetize the last send, so see if we can complete the Irp here
  1987. //
  1988. RemoveEntryList (&pSendContext->Linkage);
  1989. pSend->pSender->NumODataRequestsPending--;
  1990. pSend->pSender->NumPacketsRemaining -= pSendContext->NumPacketsRemaining;
  1991. ASSERT (pSendContext->pIrp);
  1992. if (pSendContext->NumSendsPending == 0)
  1993. {
  1994. if (pSendContext->pIrpToComplete)
  1995. {
  1996. ASSERT (pSendContext == pSendContext->pMessage2Request->pMessage2Request);
  1997. if (pSendContext->pMessage2Request)
  1998. {
  1999. ASSERT (!pSendContext->pMessage2Request->pIrpToComplete);
  2000. pSendContext->pMessage2Request->pIrpToComplete = pSendContext->pIrpToComplete;
  2001. pSendContext->pIrpToComplete = NULL;
  2002. }
  2003. pSendContext->pMessage2Request->pMessage2Request = NULL;
  2004. pSendContext->pMessage2Request = NULL;
  2005. }
  2006. PgmUnlock (pSend, *pOldIrq);
  2007. PgmReleaseResource (&pSend->pSender->Resource);
  2008. if (pSendContext->pIrpToComplete)
  2009. {
  2010. PgmIoComplete (pSendContext->pIrpToComplete, STATUS_UNSUCCESSFUL, 0);
  2011. }
  2012. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  2013. PgmAcquireResourceExclusive (&pSend->pSender->Resource, TRUE);
  2014. PgmLock (pSend, *pOldIrq);
  2015. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext);
  2016. }
  2017. else
  2018. {
  2019. pSendContext->DataPacketsPacketized = pSendContext->NumDataPacketsSent;
  2020. InsertTailList (&pSend->pSender->CompletedSendsInWindow, &pSendContext->Linkage);
  2021. }
  2022. return (status);
  2023. }
  2024. pSendContext->EndSequenceNumber = NextODataSequenceNumber - 1;
  2025. if ((pSendContext->bLastSend) &&
  2026. (!pSendContext->BytesLeftToPacketize))
  2027. {
  2028. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmPacketizeSend",
  2029. "Calling PgmSetFin since bLastSend set for last packet!\n");
  2030. pSendContext->bLastSend = FALSE;
  2031. //
  2032. // We have finished packetizing all the packets, but
  2033. // since this is the last send we also need to set the
  2034. // FIN on the last packet
  2035. //
  2036. PgmSetFin (pSend, pSendContext, pOldIrq);
  2037. }
  2038. ASSERT (!pSendContext->BytesLeftToPacketize);
  2039. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmPacketizeSend",
  2040. "TotalBytes=<%d>, BytesToPacketize=<%d>, SeqNums=[%d--%d]\n",
  2041. pSendContext->BytesInSend, BytesToPacketize,
  2042. (ULONG) pSendContext->StartSequenceNumber, (ULONG) pSendContext->EndSequenceNumber);
  2043. return (STATUS_SUCCESS);
  2044. }
  2045. //----------------------------------------------------------------------------
  2046. VOID
  2047. PgmPrepareNextSend(
  2048. IN tSEND_SESSION *pSend,
  2049. IN PGMLockHandle *pOldIrq,
  2050. IN BOOLEAN fPacketizeAll,
  2051. IN BOOLEAN fResourceLockHeld
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. This routine is called to prepare the next set of packets
  2056. for sending on the wire
  2057. The pSend lock is held before calling this routine
  2058. Arguments:
  2059. IN pSend -- Pgm session (sender) context
  2060. IN pOldIrq -- pSend's OldIrq
  2061. Return Value:
  2062. NTSTATUS - Final status of the request
  2063. --*/
  2064. {
  2065. LIST_ENTRY *pEntry;
  2066. tCLIENT_SEND_REQUEST *pSendContext;
  2067. NTSTATUS status;
  2068. //
  2069. // See if we need to packetize all pending sends or just ensure
  2070. // that we have at least 1 send avaialble
  2071. //
  2072. if ((!fPacketizeAll) &&
  2073. (!IsListEmpty (&pSend->pSender->PendingPacketizedSends)))
  2074. {
  2075. pSendContext = CONTAINING_RECORD (pSend->pSender->PendingPacketizedSends.Flink, tCLIENT_SEND_REQUEST, Linkage);
  2076. if (pSendContext->NumDataPacketsSent < pSendContext->DataPacketsPacketized)
  2077. {
  2078. //
  2079. // We have more packets to send!
  2080. //
  2081. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmPrepareNextSend",
  2082. "Have more packets -- returning since caller preferred not to packetize!\n");
  2083. return;
  2084. }
  2085. }
  2086. if (!fResourceLockHeld)
  2087. {
  2088. PgmUnlock (pSend, *pOldIrq);
  2089. PgmAcquireResourceExclusive (&pSend->pSender->Resource, TRUE);
  2090. PgmLock (pSend, *pOldIrq);
  2091. }
  2092. pSendContext = NULL;
  2093. if (!IsListEmpty (&pSend->pSender->PendingPacketizedSends))
  2094. {
  2095. //
  2096. // See if we need to packetize the remaining bytes of the last send
  2097. //
  2098. pSendContext = CONTAINING_RECORD (pSend->pSender->PendingPacketizedSends.Blink, tCLIENT_SEND_REQUEST, Linkage);
  2099. if (!pSendContext->BytesLeftToPacketize)
  2100. {
  2101. pSendContext = NULL;
  2102. }
  2103. }
  2104. while (pSend->pSender->BufferSizeAvailable)
  2105. {
  2106. //
  2107. // If we already have a send pending, see if we need to packetize
  2108. // any more packets
  2109. //
  2110. if ((!pSendContext) &&
  2111. (!IsListEmpty (&pSend->pSender->PendingSends)))
  2112. {
  2113. pEntry = RemoveHeadList (&pSend->pSender->PendingSends);
  2114. InsertTailList (&pSend->pSender->PendingPacketizedSends, pEntry);
  2115. pSendContext = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  2116. }
  2117. if (!pSendContext)
  2118. {
  2119. //
  2120. // We have no more packets to packetize!
  2121. //
  2122. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmPrepareNextSend",
  2123. "No more sends Pending!\n");
  2124. break;
  2125. }
  2126. status = PgmPacketizeSend (pSend, pSendContext, pOldIrq);
  2127. if (!NT_SUCCESS (status))
  2128. {
  2129. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmPrepareNextSend",
  2130. "PgmPacketizeSend returned <%x>\n", status);
  2131. }
  2132. else if (pSendContext->BytesLeftToPacketize)
  2133. {
  2134. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmPrepareNextSend",
  2135. "WARNING Packetizing buffer full!\n");
  2136. ASSERT (pSend->pSender->BufferSizeAvailable <
  2137. (pSend->pSender->PacketBufferSize * pSend->FECGroupSize));
  2138. break;
  2139. }
  2140. pSendContext = NULL;
  2141. }
  2142. if (!fResourceLockHeld)
  2143. {
  2144. PgmUnlock (pSend, *pOldIrq);
  2145. PgmReleaseResource (&pSend->pSender->Resource);
  2146. PgmLock (pSend, *pOldIrq);
  2147. }
  2148. return;
  2149. }
  2150. //----------------------------------------------------------------------------
  2151. VOID
  2152. PgmSendODataCompletion(
  2153. IN tCLIENT_SEND_REQUEST *pSendContext,
  2154. IN tBASIC_DATA_PACKET_HEADER *pODataBuffer,
  2155. IN NTSTATUS status
  2156. )
  2157. /*++
  2158. Routine Description:
  2159. This routine is called by the transport when the OData send has been completed
  2160. Arguments:
  2161. IN pSendContext -- Pgm's Send context
  2162. IN pUnused -- not used
  2163. IN status --
  2164. Return Value:
  2165. NONE
  2166. --*/
  2167. {
  2168. ULONG SendLength;
  2169. PGMLockHandle OldIrq;
  2170. PIRP pIrpCurrentSend = NULL;
  2171. PIRP pIrpToComplete = NULL;
  2172. tSEND_SESSION *pSend = pSendContext->pSend;
  2173. PgmLock (pSend, OldIrq);
  2174. if (NT_SUCCESS (status))
  2175. {
  2176. //
  2177. // Set the Ncf statistics
  2178. //
  2179. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendODataCompletion",
  2180. "SUCCEEDED\n");
  2181. if (!(pODataBuffer->CommonHeader.Options & PACKET_HEADER_OPTIONS_PARITY))
  2182. {
  2183. pSendContext->NumDataPacketsSentSuccessfully++;
  2184. }
  2185. }
  2186. else
  2187. {
  2188. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendODataCompletion",
  2189. "status=<%x>\n", status);
  2190. }
  2191. //
  2192. // If all the OData has been sent, we may need to complete the Irp
  2193. // Since we don't know whether we are on the CurrentSend or Completed
  2194. // Sends list, we will need to also check the Bytes
  2195. //
  2196. if ((--pSendContext->NumSendsPending == 0) && // No other sends pending
  2197. (pSendContext->NumParityPacketsToSend == 0) && // No parity packets pending
  2198. (!pSendContext->BytesLeftToPacketize) && // All bytes have been packetized
  2199. (pSendContext->NumDataPacketsSent == pSendContext->DataPacketsPacketized)) // Pkts sent == total Pkts
  2200. {
  2201. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendODataCompletion",
  2202. "Completing Send#=<%d>, pIrp=<%p> for <%d> packets, Seq=[%d, %d]\n",
  2203. pSendContext->SendNumber, pSendContext->pIrp, pSendContext->DataPacketsPacketized,
  2204. (ULONG) pSendContext->StartSequenceNumber, (ULONG) pSendContext->EndSequenceNumber);
  2205. pSend->DataBytes += pSendContext->BytesInSend;
  2206. if (pIrpCurrentSend = pSendContext->pIrp)
  2207. {
  2208. if (pSendContext->NumDataPacketsSentSuccessfully == pSendContext->NumDataPacketsSent)
  2209. {
  2210. status = STATUS_SUCCESS;
  2211. SendLength = pSendContext->BytesInSend;
  2212. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmSendODataCompletion",
  2213. "pIrp=<%p -- %p>, pSendContext=<%p>, NumPackets sent successfully = <%d/%d>\n",
  2214. pSendContext->pIrp, pSendContext->pIrpToComplete, pSendContext,
  2215. pSendContext->NumDataPacketsSentSuccessfully, pSendContext->NumDataPacketsSent);
  2216. }
  2217. else
  2218. {
  2219. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendODataCompletion",
  2220. "pIrp=<%p -- %p>, pSendContext=<%p>, NumPackets sent successfully = <%d/%d>\n",
  2221. pSendContext->pIrp, pSendContext->pIrpToComplete, pSendContext,
  2222. pSendContext->NumDataPacketsSentSuccessfully, pSendContext->NumDataPacketsSent);
  2223. status = STATUS_UNSUCCESSFUL;
  2224. SendLength = 0;
  2225. }
  2226. pSendContext->pIrp = NULL;
  2227. pIrpToComplete = pSendContext->pIrpToComplete;
  2228. }
  2229. else
  2230. {
  2231. ASSERT (0); // To verify there is no double completion!
  2232. }
  2233. if (pSendContext->pMessage2Request)
  2234. {
  2235. //
  2236. // We could have a situation where the send was split into 2, and
  2237. // the second send could either be in the PendingSends list or
  2238. // the PendingPacketizedSends list, or the CompletedSendsInWindow list
  2239. //
  2240. // We should have the other send complete the Irp and delink ourselves
  2241. //
  2242. ASSERT (pSendContext == pSendContext->pMessage2Request->pMessage2Request);
  2243. if (pIrpToComplete)
  2244. {
  2245. ASSERT (!pSendContext->pMessage2Request->pIrpToComplete);
  2246. pSendContext->pMessage2Request->pIrpToComplete = pSendContext->pIrpToComplete;
  2247. pIrpToComplete = pSendContext->pIrpToComplete = NULL;
  2248. }
  2249. pSendContext->pMessage2Request->pMessage2Request = NULL;
  2250. pSendContext->pMessage2Request = NULL;
  2251. }
  2252. }
  2253. PgmUnlock (pSend, OldIrq);
  2254. if (pODataBuffer)
  2255. {
  2256. ExFreeToNPagedLookasideList (&pSend->pSender->SenderBufferLookaside, pODataBuffer);
  2257. }
  2258. if (pIrpCurrentSend)
  2259. {
  2260. if (pIrpToComplete)
  2261. {
  2262. PgmIoComplete (pIrpToComplete, status, SendLength);
  2263. }
  2264. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  2265. }
  2266. }
  2267. //----------------------------------------------------------------------------
  2268. VOID
  2269. PgmBuildDataPacket(
  2270. IN tSEND_SESSION *pSend,
  2271. IN tCLIENT_SEND_REQUEST *pSendContext,
  2272. IN tPACKET_BUFFER *pPacketBuffer,
  2273. IN PUCHAR pSendBuffer,
  2274. IN USHORT *pSendBufferLength
  2275. )
  2276. {
  2277. ULONG i;
  2278. ULONG LateJoinerSequence;
  2279. SEQ_TYPE FECGroupMask = pSend->FECGroupSize-1;
  2280. tSEND_CONTEXT *pSender = pSend->pSender;
  2281. tPACKET_OPTION_GENERIC UNALIGNED *pOptionHeader;
  2282. tBASIC_DATA_PACKET_HEADER UNALIGNED *pODataBuffer = (tBASIC_DATA_PACKET_HEADER UNALIGNED *)
  2283. &pPacketBuffer->DataPacket;
  2284. //
  2285. // Get the SendLength and fill in the remaining fields of this send (Trailing edge + checksum)
  2286. //
  2287. *pSendBufferLength = pPacketBuffer->PacketOptions.TotalPacketLength;
  2288. if (pPacketBuffer->PacketOptions.OptionsFlags & PGM_OPTION_FLAG_JOIN)
  2289. {
  2290. ASSERT (pODataBuffer->CommonHeader.Options & PACKET_HEADER_OPTIONS_PRESENT);
  2291. if (pPacketBuffer->PacketOptions.LateJoinerOptionOffset)
  2292. {
  2293. if (SEQ_GT (pSend->pSender->LastODataSentSequenceNumber, (pSend->pSender->TrailingGroupSequenceNumber +
  2294. pSend->pSender->LateJoinSequenceNumbers)))
  2295. {
  2296. LateJoinerSequence = (ULONG) (SEQ_TYPE) (pSend->pSender->LastODataSentSequenceNumber -
  2297. pSend->pSender->LateJoinSequenceNumbers);
  2298. }
  2299. else
  2300. {
  2301. LateJoinerSequence = (ULONG) (SEQ_TYPE) pSend->pSender->TrailingGroupSequenceNumber;
  2302. }
  2303. pPacketBuffer->PacketOptions.LateJoinerSequence = LateJoinerSequence;
  2304. pOptionHeader = (tPACKET_OPTION_GENERIC UNALIGNED *) &((PUCHAR) (pODataBuffer + 1)) [pPacketBuffer->PacketOptions.LateJoinerOptionOffset];
  2305. LateJoinerSequence = htonl (LateJoinerSequence);
  2306. PgmCopyMemory ((pOptionHeader + 1), &LateJoinerSequence, (sizeof(ULONG)));
  2307. }
  2308. else
  2309. {
  2310. ASSERT (0);
  2311. }
  2312. }
  2313. PgmCopyMemory (pSendBuffer, pODataBuffer, *pSendBufferLength);
  2314. //
  2315. // Now, see if we need to build the parity context for the first
  2316. // pro-active parity packet following this one
  2317. //
  2318. if ((pSend->FECProActivePackets) && // Need to send FEC pro-active packets
  2319. (pSendContext->NumParityPacketsToSend == pSend->FECProActivePackets))
  2320. {
  2321. //
  2322. // Start from the Group leader packet
  2323. //
  2324. ASSERT (pSender->pLastProActiveGroupLeader);
  2325. pPacketBuffer = pSender->pLastProActiveGroupLeader;
  2326. pSendBuffer = (PUCHAR) pPacketBuffer;
  2327. pSender->pProActiveParityContext->OptionsFlags = 0;
  2328. pSender->pProActiveParityContext->NumPacketsInThisGroup = 0;
  2329. for (i=0; i<pSend->FECGroupSize; i++)
  2330. {
  2331. pSender->pProActiveParityContext->pDataBuffers[i] = &((PUCHAR) &pPacketBuffer->DataPacket)[sizeof (tBASIC_DATA_PACKET_HEADER) +
  2332. pPacketBuffer->PacketOptions.OptionsLength];
  2333. pSender->pProActiveParityContext->OptionsFlags |= pPacketBuffer->PacketOptions.OptionsFlags &
  2334. (PGM_OPTION_FLAG_SYN |
  2335. PGM_OPTION_FLAG_FIN |
  2336. PGM_OPTION_FLAG_FRAGMENT |
  2337. PGM_OPTION_FLAG_PARITY_CUR_TGSIZE);
  2338. if (pPacketBuffer->PacketOptions.OptionsFlags & PGM_OPTION_FLAG_PARITY_CUR_TGSIZE)
  2339. {
  2340. ASSERT (!pSender->pProActiveParityContext->NumPacketsInThisGroup);
  2341. ASSERT (pPacketBuffer->PacketOptions.FECContext.NumPacketsInThisGroup);
  2342. pSender->pProActiveParityContext->NumPacketsInThisGroup = pPacketBuffer->PacketOptions.FECContext.NumPacketsInThisGroup;
  2343. }
  2344. pSendBuffer += pSender->PacketBufferSize;
  2345. pPacketBuffer = (tPACKET_BUFFER *) pSendBuffer;
  2346. }
  2347. if (!(pSender->pProActiveParityContext->OptionsFlags & PGM_OPTION_FLAG_PARITY_CUR_TGSIZE))
  2348. {
  2349. ASSERT (!pSender->pProActiveParityContext->NumPacketsInThisGroup);
  2350. pSender->pProActiveParityContext->NumPacketsInThisGroup = pSend->FECGroupSize;
  2351. }
  2352. }
  2353. }
  2354. //----------------------------------------------------------------------------
  2355. NTSTATUS
  2356. PgmSendNextOData(
  2357. IN tSEND_SESSION *pSend,
  2358. IN PGMLockHandle *pOldIrq,
  2359. OUT ULONG *pBytesSent
  2360. )
  2361. /*++
  2362. Routine Description:
  2363. This routine is called to send a Data (OData) packet
  2364. The pSend lock is held before calling this routine
  2365. Arguments:
  2366. IN pSend -- Pgm session (sender) context
  2367. IN pOldIrq -- pSend's OldIrq
  2368. OUT pBytesSent -- Set if send succeeded (used for calculating throughput)
  2369. Return Value:
  2370. NTSTATUS - Final status of the send request
  2371. --*/
  2372. {
  2373. NTSTATUS status = STATUS_SUCCESS;
  2374. ULONG i, XSum;
  2375. USHORT SendBufferLength;
  2376. KAPC_STATE ApcState;
  2377. BOOLEAN fAttached;
  2378. BOOLEAN fSendingFECPacket = FALSE;
  2379. BOOLEAN fResetOptions = FALSE;
  2380. tBASIC_DATA_PACKET_HEADER *pODataBuffer = NULL;
  2381. PUCHAR pSendBuffer = NULL;
  2382. tCLIENT_SEND_REQUEST *pSendContext;
  2383. tPACKET_OPTIONS PacketOptions;
  2384. tPACKET_BUFFER *pPacketBuffer;
  2385. ULONG OptionValue;
  2386. SEQ_TYPE FECGroupMask = pSend->FECGroupSize-1;
  2387. UCHAR EmptyPackets = 0;
  2388. tSEND_CONTEXT *pSender = pSend->pSender;
  2389. *pBytesSent = 0; // Initialize
  2390. pODataBuffer = NULL;
  2391. if (IsListEmpty (&pSender->PendingPacketizedSends))
  2392. {
  2393. ASSERT (!IsListEmpty (&pSender->PendingSends));
  2394. PgmPrepareNextSend (pSend, pOldIrq, FALSE, FALSE);
  2395. return (STATUS_SUCCESS);
  2396. }
  2397. pSendContext = CONTAINING_RECORD (pSender->PendingPacketizedSends.Flink, tCLIENT_SEND_REQUEST, Linkage);
  2398. //
  2399. // This routine is called only if we have a packet to send, so
  2400. // set pODataBuffer to the packet to be sent
  2401. // NumDataPacketsSent and DataPacketsPacketized should both be 0 for a fresh send
  2402. // They will be equal if we had run out of Buffer space for the last
  2403. // packetization (i.e. Send length > available buffer space)
  2404. //
  2405. SendBufferLength = PGM_MAX_FEC_DATA_HEADER_LENGTH + (USHORT) pSender->MaxPayloadSize;
  2406. if (!(pSendBuffer = ExAllocateFromNPagedLookasideList (&pSender->SenderBufferLookaside)))
  2407. {
  2408. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendNextOData",
  2409. "STATUS_INSUFFICIENT_RESOURCES\n");
  2410. return (STATUS_INSUFFICIENT_RESOURCES);
  2411. }
  2412. //
  2413. // See if we need to set the FIN flag
  2414. //
  2415. if ((pSendContext->bLastSend) &&
  2416. (!pSendContext->BytesLeftToPacketize))
  2417. {
  2418. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmSendNextOData",
  2419. "Calling PgmSetFin since bLastSend set for last packet!\n");
  2420. pSendContext->bLastSend = FALSE;
  2421. //
  2422. // We have finished packetizing all the packets, but
  2423. // since this is the last send we also need to set the
  2424. // FIN on the last packet
  2425. //
  2426. PgmSetFin (pSend, pSendContext, pOldIrq);
  2427. }
  2428. if (pSendContext->NumParityPacketsToSend)
  2429. {
  2430. //
  2431. // Release the Send lock and attach to the SectionMap process
  2432. // to compute the parity packet
  2433. //
  2434. PgmUnlock (pSend, *pOldIrq);
  2435. PgmAttachToProcessForVMAccess (pSend->Process, &ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  2436. status = PgmBuildParityPacket (pSend,
  2437. pSend->pSender->pLastProActiveGroupLeader,
  2438. pSender->pProActiveParityContext,
  2439. (PUCHAR) pSendBuffer,
  2440. &SendBufferLength,
  2441. PACKET_TYPE_ODATA);
  2442. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  2443. PgmLock (pSend, *pOldIrq);
  2444. if (!NT_SUCCESS (status))
  2445. {
  2446. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSendNextOData",
  2447. "PgmBuildParityPacket returned <%x>\n", status);
  2448. ExFreeToNPagedLookasideList (&pSender->SenderBufferLookaside, pSendBuffer);
  2449. return (STATUS_SUCCESS);
  2450. }
  2451. pODataBuffer = (tBASIC_DATA_PACKET_HEADER *) pSendBuffer;
  2452. ASSERT (SendBufferLength <= (PGM_MAX_FEC_DATA_HEADER_LENGTH +
  2453. htons (pODataBuffer->CommonHeader.TSDULength)));
  2454. fSendingFECPacket = TRUE;
  2455. pSendContext->NumParityPacketsToSend--;
  2456. pSendContext->NumSendsPending++;
  2457. }
  2458. else if (pSendContext->NumDataPacketsSent < pSendContext->DataPacketsPacketized)
  2459. {
  2460. //
  2461. // Verify that this send has already been packetized
  2462. //
  2463. ASSERT (pSendContext->BytesLeftToPacketize < pSendContext->BytesInSend);
  2464. //
  2465. // Get the current send packet and send length
  2466. //
  2467. pPacketBuffer = (tPACKET_BUFFER *) (pSender->SendDataBufferMapping + pSendContext->NextPacketOffset);
  2468. pODataBuffer = &pPacketBuffer->DataPacket;
  2469. pSendContext->NumSendsPending++;
  2470. if (0 == pSendContext->NumDataPacketsSent++)
  2471. {
  2472. pSendContext->SendStartTime = pSend->pSender->TimerTickCount;
  2473. }
  2474. //
  2475. // Update the sender parameters
  2476. //
  2477. pSender->LastODataSentSequenceNumber++;
  2478. if (pSend->FECOptions) // Need to send FEC pro-active packets
  2479. {
  2480. //
  2481. // See if we are at the end of a variable TG send
  2482. //
  2483. if (pODataBuffer == pSendContext->pLastMessageVariableTGPacket)
  2484. {
  2485. pSender->LastVariableTGPacketSequenceNumber = pSender->LastODataSentSequenceNumber;
  2486. EmptyPackets = (UCHAR) (FECGroupMask - (pSender->LastODataSentSequenceNumber & FECGroupMask));
  2487. pSendContext->NumParityPacketsToSend = pSend->FECProActivePackets;
  2488. }
  2489. //
  2490. // Otherwise see if the next send needs to be for pro-active parity
  2491. //
  2492. else if ((pSend->FECProActivePackets) && // Need to send FEC pro-active packets
  2493. (FECGroupMask == (pSender->LastODataSentSequenceNumber & FECGroupMask))) // Last Packet In Group
  2494. {
  2495. pSendContext->NumParityPacketsToSend = pSend->FECProActivePackets;
  2496. }
  2497. //
  2498. // If this is the GroupLeader packet, and we have pro-active parity enabled,
  2499. // then we need to set the buffer information for computing the FEC packets
  2500. //
  2501. if ((pSend->FECProActivePackets) && // Need to send FEC pro-active packets
  2502. (0 == (pSender->LastODataSentSequenceNumber & FECGroupMask))) // GroupLeader
  2503. {
  2504. pSender->pLastProActiveGroupLeader = pPacketBuffer;
  2505. }
  2506. }
  2507. //
  2508. // Since we will be accessing the buffer, we will need to release the
  2509. // lock to get at passive Irql + attach to the process
  2510. //
  2511. PgmUnlock (pSend, *pOldIrq);
  2512. PgmAttachToProcessForVMAccess (pSend->Process, &ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  2513. PgmBuildDataPacket (pSend, pSendContext, pPacketBuffer, pSendBuffer, &SendBufferLength);
  2514. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_PACKETIZE);
  2515. PgmLock (pSend, *pOldIrq);
  2516. pODataBuffer = (tBASIC_DATA_PACKET_HEADER *) pSendBuffer;
  2517. //
  2518. // Verify that the packet we are sending is what we think we are sending!
  2519. //
  2520. ASSERT (ntohl(pODataBuffer->DataSequenceNumber) == (LONG) pSender->LastODataSentSequenceNumber);
  2521. pSender->EmptySequencesForLastSend = EmptyPackets;
  2522. pSender->LastODataSentSequenceNumber += EmptyPackets;
  2523. }
  2524. else
  2525. {
  2526. ExFreeToNPagedLookasideList (&pSender->SenderBufferLookaside, pSendBuffer);
  2527. pSendBuffer = NULL;
  2528. }
  2529. //
  2530. // Now, set the parameters for the next send
  2531. //
  2532. if ((pSendBuffer) &&
  2533. (!pSendContext->NumParityPacketsToSend)) // Verify no pro-active parity packets following this
  2534. {
  2535. pSendContext->NextPacketOffset += ((1 + EmptyPackets) * pSender->PacketBufferSize);
  2536. if (pSendContext->NextPacketOffset >= pSender->MaxDataFileSize)
  2537. {
  2538. pSendContext->NextPacketOffset = 0; // We need to wrap around!
  2539. }
  2540. }
  2541. //
  2542. // If we have sent all the data for this Send (or however many bytes
  2543. // we had packetized from this send), we need to packetize more packets
  2544. //
  2545. if ((pSendContext->NumDataPacketsSent == pSendContext->DataPacketsPacketized) &&
  2546. (!pSendContext->NumParityPacketsToSend))
  2547. {
  2548. //
  2549. // If we are done with this send, move it to the CompletedSends list
  2550. // The last send completion will complete the Send Irp
  2551. //
  2552. if (!pSendContext->BytesLeftToPacketize)
  2553. {
  2554. ASSERT (pSend->pSender->LastODataSentSequenceNumber == pSendContext->EndSequenceNumber);
  2555. ASSERT (pSendContext->NumSendsPending);
  2556. RemoveEntryList (&pSendContext->Linkage);
  2557. InsertTailList (&pSender->CompletedSendsInWindow, &pSendContext->Linkage);
  2558. pSender->NumODataRequestsPending--;
  2559. //
  2560. // If the last packet on this Send had a FIN, we will need to
  2561. // follow this send with an Ambient SPM including the FIN flag
  2562. //
  2563. ASSERT (!pSendContext->bLastSend);
  2564. if (pSendContext->DataOptions & PGM_OPTION_FLAG_FIN)
  2565. {
  2566. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmSendNextOData",
  2567. "Setting FIN since client closed session!\n");
  2568. pSender->SpmOptions |= PGM_OPTION_FLAG_FIN;
  2569. pSender->CurrentSPMTimeout = pSender->AmbientSPMTimeout;
  2570. pSend->SessionFlags |= PGM_SESSION_FLAG_SEND_AMBIENT_SPM;
  2571. }
  2572. }
  2573. PgmPrepareNextSend (pSend, pOldIrq, FALSE, FALSE);
  2574. }
  2575. if (!pSendBuffer)
  2576. {
  2577. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmSendNextOData",
  2578. "Setting FIN since client closed session!\n");
  2579. //
  2580. // This was the case of a new Send waiting to be packetized
  2581. // Return success here, and we should get called again for the
  2582. // actual send
  2583. //
  2584. return (STATUS_SUCCESS);
  2585. }
  2586. PgmUnlock (pSend, *pOldIrq);
  2587. pODataBuffer->TrailingEdgeSequenceNumber = htonl ((ULONG) pSender->TrailingGroupSequenceNumber);
  2588. XSum = 0;
  2589. pODataBuffer->CommonHeader.Checksum = 0;
  2590. XSum = tcpxsum (XSum, (CHAR *) pODataBuffer, SendBufferLength); // Compute the Checksum
  2591. pODataBuffer->CommonHeader.Checksum = (USHORT) (~XSum);
  2592. status = TdiSendDatagram (pSender->pAddress->pFileObject,
  2593. pSender->pAddress->pDeviceObject,
  2594. pODataBuffer,
  2595. (ULONG) SendBufferLength,
  2596. PgmSendODataCompletion, // Completion
  2597. pSendContext, // Context1
  2598. pODataBuffer, // Context2
  2599. pSender->DestMCastIpAddress,
  2600. pSender->DestMCastPort);
  2601. ASSERT (NT_SUCCESS (status));
  2602. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "PgmSendNextOData",
  2603. "[%d-%d] -- Sent <%d> bytes to <%x:%d>\n",
  2604. (ULONG) pSender->TrailingGroupSequenceNumber,
  2605. (ULONG) pSender->LastODataSentSequenceNumber,
  2606. SendBufferLength, pSender->DestMCastIpAddress, pSender->DestMCastPort);
  2607. PgmLock (pSend, *pOldIrq);
  2608. *pBytesSent = SendBufferLength;
  2609. return (status);
  2610. }
  2611. //----------------------------------------------------------------------------
  2612. VOID
  2613. PgmCancelAllSends(
  2614. IN tSEND_SESSION *pSend,
  2615. IN LIST_ENTRY *pListEntry,
  2616. IN PIRP pIrp
  2617. )
  2618. /*++
  2619. Routine Description:
  2620. This routine handles the cancelling of a Send Irp. It must release the
  2621. cancel spin lock before returning re: IoCancelIrp().
  2622. Arguments:
  2623. Return Value:
  2624. None
  2625. --*/
  2626. {
  2627. PLIST_ENTRY pEntry;
  2628. tCLIENT_SEND_REQUEST *pSendContext;
  2629. PIRP pIrpToComplete = NULL;
  2630. SEQ_TYPE HighestLeadSeq;
  2631. ULONG NumExSequencesInOldWindow, NumRequests = 0;
  2632. ULONGLONG BufferSpaceFreed;
  2633. //
  2634. // Now cancel all the remaining send requests because the integrity
  2635. // of the data cannot be guaranteed
  2636. // We also have to deal with the fact that some Irps may have
  2637. // data in the transport (i.e. possibly the first send on the Packetized
  2638. // list, or the last send of the completed list)
  2639. //
  2640. // We will start with the unpacketized requests
  2641. //
  2642. while (!IsListEmpty (&pSend->pSender->PendingSends))
  2643. {
  2644. pEntry = RemoveHeadList (&pSend->pSender->PendingSends);
  2645. pSendContext = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  2646. InsertTailList (pListEntry, pEntry);
  2647. NumRequests++;
  2648. ASSERT (!pSendContext->NumSendsPending);
  2649. //
  2650. // If this is a partial send, we will mark the Irp for completion
  2651. // initially to the companion send request (to avoid complications
  2652. // of Sends pending in the transport here)
  2653. //
  2654. if (pSendContext->pMessage2Request)
  2655. {
  2656. //
  2657. // pMessage2Request could either be on the PendingPacketizedSends
  2658. // list or on the Completed Sends list (awaiting a send completion)
  2659. //
  2660. ASSERT (pSendContext->pMessage2Request->pIrp);
  2661. if (pSendContext->pIrpToComplete)
  2662. {
  2663. ASSERT (!pSendContext->pMessage2Request->pIrpToComplete);
  2664. pSendContext->pMessage2Request->pIrpToComplete = pSendContext->pIrpToComplete;
  2665. pSendContext->pIrpToComplete = NULL;
  2666. }
  2667. pSendContext->pMessage2Request->pMessage2Request = NULL;
  2668. pSendContext->pMessage2Request = NULL;
  2669. }
  2670. ASSERT (pSendContext->BytesLeftToPacketize == pSendContext->BytesInSend);
  2671. pSend->pSender->NumODataRequestsPending--;
  2672. pSend->pSender->NumPacketsRemaining -= pSendContext->NumPacketsRemaining;
  2673. }
  2674. //
  2675. // Now, go through all the sends which have already been packetized
  2676. // except for the first one which we will handle below
  2677. //
  2678. HighestLeadSeq = pSend->pSender->NextODataSequenceNumber;
  2679. pEntry = pSend->pSender->PendingPacketizedSends.Flink;
  2680. while ((pEntry = pEntry->Flink) != &pSend->pSender->PendingPacketizedSends)
  2681. {
  2682. pSendContext = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  2683. pEntry = pEntry->Blink;
  2684. RemoveEntryList (&pSendContext->Linkage);
  2685. InsertTailList (pListEntry, &pSendContext->Linkage);
  2686. pSend->pSender->NumODataRequestsPending--;
  2687. pSend->pSender->NumPacketsRemaining -= pSendContext->NumPacketsRemaining;
  2688. NumRequests++;
  2689. if (SEQ_LT (pSendContext->StartSequenceNumber, HighestLeadSeq))
  2690. {
  2691. HighestLeadSeq = pSendContext->StartSequenceNumber;
  2692. }
  2693. ASSERT ((!pSendContext->NumDataPacketsSent) && (!pSendContext->NumSendsPending));
  2694. if (pSendContext->pMessage2Request)
  2695. {
  2696. //
  2697. // pMessage2Request could either be on the PendingPacketizedSends
  2698. // list or on the Completed Sends list (awaiting a send completion)
  2699. //
  2700. ASSERT (pSendContext->pMessage2Request->pIrp);
  2701. if (pSendContext->pIrpToComplete)
  2702. {
  2703. ASSERT (!pSendContext->pMessage2Request->pIrpToComplete);
  2704. pSendContext->pMessage2Request->pIrpToComplete = pSendContext->pIrpToComplete;
  2705. pSendContext->pIrpToComplete = NULL;
  2706. }
  2707. pSendContext->pMessage2Request->pMessage2Request = NULL;
  2708. pSendContext->pMessage2Request = NULL;
  2709. }
  2710. }
  2711. //
  2712. // Terminate the first PendingPacketizedSend only if we have not
  2713. // yet started sending it or this Cancel was meant for that request
  2714. // (Try to protect data integrity as much as possible)
  2715. //
  2716. if (!IsListEmpty (&pSend->pSender->PendingPacketizedSends))
  2717. {
  2718. pSendContext = CONTAINING_RECORD (pSend->pSender->PendingPacketizedSends.Flink, tCLIENT_SEND_REQUEST, Linkage);
  2719. if ((!pSendContext->NumDataPacketsSent) ||
  2720. (!pIrp || (pSendContext->pIrp == pIrp)))
  2721. {
  2722. RemoveEntryList (&pSendContext->Linkage);
  2723. ASSERT (IsListEmpty (&pSend->pSender->PendingPacketizedSends));
  2724. NumRequests++;
  2725. //
  2726. // If we have some data pending in the transport,
  2727. // then we will have to let the SendCompletion handle that
  2728. //
  2729. ASSERT ((pSendContext->NumDataPacketsSent < pSendContext->DataPacketsPacketized) ||
  2730. (pSendContext->NumParityPacketsToSend));
  2731. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmCancelAllSends",
  2732. "Partial Send, pIrp=<%p>, BytesLeftToPacketize=<%d/%d>, PacketsSent=<%d/%d>, Pending=<%d>\n",
  2733. pSendContext->pIrp, pSendContext->BytesLeftToPacketize,
  2734. pSendContext->BytesInSend, pSendContext->NumDataPacketsSent,
  2735. pSendContext->DataPacketsPacketized, pSendContext->NumSendsPending);
  2736. pSendContext->BytesLeftToPacketize = 0;
  2737. pSendContext->DataPacketsPacketized = pSendContext->NumDataPacketsSent;
  2738. pSendContext->NumParityPacketsToSend = 0;
  2739. pSend->pSender->NumODataRequestsPending--;
  2740. pSend->pSender->NumPacketsRemaining -= pSendContext->NumPacketsRemaining;
  2741. if (pSendContext->NumSendsPending)
  2742. {
  2743. InsertTailList (&pSend->pSender->CompletedSendsInWindow, &pSendContext->Linkage);
  2744. }
  2745. else
  2746. {
  2747. //
  2748. // If we have a companion partial, then it must be in the completed list
  2749. // awaiting SendCompletion
  2750. //
  2751. if (pSendContext->pMessage2Request)
  2752. {
  2753. ASSERT (pSendContext->pMessage2Request->pIrp);
  2754. if (pSendContext->pIrpToComplete)
  2755. {
  2756. ASSERT (!pSendContext->pMessage2Request->BytesLeftToPacketize);
  2757. ASSERT (!pSendContext->pMessage2Request->pIrpToComplete);
  2758. pSendContext->pMessage2Request->pIrpToComplete = pSendContext->pIrpToComplete;
  2759. pSendContext->pIrpToComplete = NULL;
  2760. }
  2761. pSendContext->pMessage2Request->pMessage2Request = NULL;
  2762. pSendContext->pMessage2Request = NULL;
  2763. }
  2764. InsertTailList (pListEntry, &pSendContext->Linkage);
  2765. }
  2766. pSendContext->EndSequenceNumber = pSend->pSender->LastODataSentSequenceNumber;
  2767. HighestLeadSeq = pSend->pSender->LastODataSentSequenceNumber + 1;
  2768. }
  2769. }
  2770. NumExSequencesInOldWindow = (ULONG) (SEQ_TYPE) (pSend->pSender->NextODataSequenceNumber-HighestLeadSeq);
  2771. BufferSpaceFreed = NumExSequencesInOldWindow * pSend->pSender->PacketBufferSize;
  2772. if (NumExSequencesInOldWindow)
  2773. {
  2774. pSend->SessionFlags |= PGM_SESSION_SENDS_CANCELLED;
  2775. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmCancelAllSends",
  2776. "[%d]: NumSeqs=<%d>, NextOData=<%d-->%d>, BuffFreeed=<%d>, LeadingOffset=<%d-->%d>\n",
  2777. NumRequests, NumExSequencesInOldWindow,
  2778. (ULONG) pSend->pSender->NextODataSequenceNumber, (ULONG) HighestLeadSeq,
  2779. (ULONG) BufferSpaceFreed, (ULONG) pSend->pSender->LeadingWindowOffset,
  2780. (ULONG) (pSend->pSender->LeadingWindowOffset - BufferSpaceFreed));
  2781. }
  2782. pSend->pSender->NextODataSequenceNumber = HighestLeadSeq;
  2783. pSend->pSender->BufferSizeAvailable += BufferSpaceFreed;
  2784. ASSERT (pSend->pSender->BufferSizeAvailable <= pSend->pSender->MaxDataFileSize);
  2785. if (pSend->pSender->LeadingWindowOffset >= BufferSpaceFreed)
  2786. {
  2787. pSend->pSender->LeadingWindowOffset -= BufferSpaceFreed;
  2788. }
  2789. else
  2790. {
  2791. pSend->pSender->LeadingWindowOffset = pSend->pSender->MaxDataFileSize - (BufferSpaceFreed - pSend->pSender->LeadingWindowOffset);
  2792. }
  2793. }
  2794. //----------------------------------------------------------------------------
  2795. ULONG
  2796. AdvanceWindow(
  2797. IN tSEND_SESSION *pSend
  2798. )
  2799. /*++
  2800. Routine Description:
  2801. This routine is called to check if we need to advance the
  2802. trailing window, and does so as appropriate
  2803. The pSend lock is held before calling this routine
  2804. Arguments:
  2805. IN pSend -- Pgm session (sender) context
  2806. Return Value:
  2807. TRUE if the send window buffer is empty, FALSE otherwise
  2808. --*/
  2809. {
  2810. LIST_ENTRY *pEntry;
  2811. tCLIENT_SEND_REQUEST *pSendContextLast;
  2812. tCLIENT_SEND_REQUEST *pSendContext1;
  2813. tSEND_RDATA_CONTEXT *pRDataContext;
  2814. SEQ_TYPE HighestTrailSeq, MaxSequencesToAdvance, SequencesInSend;
  2815. ULONGLONG PreferredTrailTime = 0;
  2816. ULONG NumExSequencesInOldWindow = 0;
  2817. //
  2818. // See if we need to increment the Trailing edge of our transmit window
  2819. //
  2820. if (pSend->pSender->TimerTickCount > pSend->pSender->NextWindowAdvanceTime)
  2821. {
  2822. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "AdvanceWindow",
  2823. "Advancing NextWindowAdvanceTime -- TimerTC = [%d:%d] >= NextWinAdvT [%d:%d]\n",
  2824. pSend->pSender->TimerTickCount, pSend->pSender->NextWindowAdvanceTime);
  2825. pSend->pSender->NextWindowAdvanceTime = pSend->pSender->TimerTickCount +
  2826. pSend->pSender->WindowAdvanceDeltaTime;
  2827. }
  2828. PreferredTrailTime = (pSend->pSender->NextWindowAdvanceTime - pSend->pSender->WindowAdvanceDeltaTime) -
  2829. pSend->pSender->WindowSizeTime;
  2830. //
  2831. // Determine the maximum sequences we can advance by (initially all seqs in window)
  2832. //
  2833. MaxSequencesToAdvance = pSend->pSender->LastODataSentSequenceNumber -
  2834. pSend->pSender->TrailingEdgeSequenceNumber + 1;
  2835. //
  2836. // If we are required to advance the window on-demand, then we
  2837. // will need to limit the Maximum sequences we can advance by
  2838. //
  2839. if ((pSend->pSender->pAddress->Flags & PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE) &&
  2840. !(pSend->SessionFlags & PGM_SESSION_DISCONNECT_INDICATED))
  2841. {
  2842. if (MaxSequencesToAdvance > (pSend->pSender->MaxPacketsInBuffer >> 1))
  2843. {
  2844. MaxSequencesToAdvance -= (ULONG) (pSend->pSender->MaxPacketsInBuffer >> 1);
  2845. }
  2846. else
  2847. {
  2848. MaxSequencesToAdvance = 0;
  2849. }
  2850. }
  2851. if ((MaxSequencesToAdvance) &&
  2852. (PreferredTrailTime >= pSend->pSender->TrailingEdgeTime)) // need to reset our current trailing edge
  2853. {
  2854. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "AdvanceWindow",
  2855. "PreferredTrail=[%d:%d] > TrailingEdge=[%d:%d], WinAdvMSecs=<%d:%d>, WinSizeMSecs=<%d:%d>\n",
  2856. PreferredTrailTime, pSend->pSender->TrailingEdgeTime, pSend->pSender->WindowAdvanceDeltaTime,
  2857. pSend->pSender->WindowSizeTime);
  2858. //
  2859. // First determine what is the maximum limit we can advance the
  2860. // window to (dependent on pending RData and send completions)
  2861. //
  2862. HighestTrailSeq = pSend->pSender->NextODataSequenceNumber & ~((SEQ_TYPE) pSend->FECGroupSize-1); // Init
  2863. // Start with pending RData requests
  2864. if (!IsListEmpty (&pSend->pSender->PendingRDataRequests))
  2865. {
  2866. //
  2867. // This list is ordered, so just compare with the first entry
  2868. //
  2869. pEntry = pSend->pSender->PendingRDataRequests.Flink;
  2870. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  2871. if (SEQ_LT (pRDataContext->RDataSequenceNumber, HighestTrailSeq))
  2872. {
  2873. HighestTrailSeq = pRDataContext->RDataSequenceNumber;
  2874. }
  2875. }
  2876. // Now, verify that the handled RData requests do not need this
  2877. // buffer memory (i.e. the Sends have completed)
  2878. pEntry = &pSend->pSender->HandledRDataRequests;
  2879. while ((pEntry = pEntry->Flink) != &pSend->pSender->HandledRDataRequests)
  2880. {
  2881. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  2882. if ((!pRDataContext->CleanupTime) && // CleanupTime is 0 for pending sends
  2883. SEQ_LT (pRDataContext->RDataSequenceNumber, HighestTrailSeq))
  2884. {
  2885. HighestTrailSeq = pRDataContext->RDataSequenceNumber;
  2886. }
  2887. }
  2888. // Now, check the completed sends list
  2889. pSendContextLast = pSendContext1 = NULL;
  2890. pEntry = &pSend->pSender->CompletedSendsInWindow;
  2891. while ((pEntry = pEntry->Flink) != &pSend->pSender->CompletedSendsInWindow)
  2892. {
  2893. pSendContext1 = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  2894. ASSERT (SEQ_GEQ (pSendContext1->EndSequenceNumber, pSend->pSender->TrailingEdgeSequenceNumber));
  2895. if (SEQ_GT (pSend->pSender->TrailingEdgeSequenceNumber, pSendContext1->StartSequenceNumber))
  2896. {
  2897. SequencesInSend = pSendContext1->EndSequenceNumber - pSend->pSender->TrailingEdgeSequenceNumber + 1;
  2898. }
  2899. else
  2900. {
  2901. SequencesInSend = pSendContext1->EndSequenceNumber - pSendContext1->StartSequenceNumber + 1;
  2902. }
  2903. if ((pSendContext1->NumSendsPending) || // Cannot advance if completions are pending
  2904. (pSendContext1->SendStartTime >= PreferredTrailTime) ||
  2905. (MaxSequencesToAdvance < SequencesInSend))
  2906. {
  2907. if (SEQ_LT (pSendContext1->StartSequenceNumber, HighestTrailSeq))
  2908. {
  2909. HighestTrailSeq = pSendContext1->StartSequenceNumber;
  2910. }
  2911. break;
  2912. }
  2913. else if (SEQ_GEQ (pSendContext1->StartSequenceNumber, HighestTrailSeq))
  2914. {
  2915. break;
  2916. }
  2917. ASSERT (MaxSequencesToAdvance);
  2918. if (pSendContextLast)
  2919. {
  2920. MaxSequencesToAdvance -= (pSendContextLast->EndSequenceNumber -
  2921. pSendContextLast->StartSequenceNumber + 1);
  2922. // Remove the send that is definitely out of the new window
  2923. RemoveEntryList (&pSendContextLast->Linkage);
  2924. ASSERT ((!pSendContextLast->pMessage2Request) && (!pSendContextLast->pIrp));
  2925. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside,pSendContextLast);
  2926. }
  2927. pSendContextLast = pSendContext1;
  2928. }
  2929. //
  2930. // pSendContext1 will be NULL if there are no completed sends,
  2931. // in which case we may have 1 huge current send that could be hogging
  2932. // our buffer, so check that then!
  2933. //
  2934. if ((!pSendContext1) &&
  2935. (!IsListEmpty (&pSend->pSender->PendingPacketizedSends)))
  2936. {
  2937. pSendContextLast = CONTAINING_RECORD (pSend->pSender->PendingPacketizedSends.Flink, tCLIENT_SEND_REQUEST, Linkage);
  2938. if ((pSendContextLast->NumSendsPending) || // Ensure no sends pending
  2939. (pSendContextLast->NumParityPacketsToSend) || // No parity packets left to send
  2940. (!pSendContextLast->NumDataPacketsSent) || // No packets sent yet
  2941. (pSendContextLast->DataPacketsPacketized != pSendContextLast->NumDataPacketsSent))
  2942. {
  2943. pSendContextLast = NULL;
  2944. }
  2945. }
  2946. //
  2947. // pSendContextLast will be non-NULL if we need to advance
  2948. // the Trailing edge
  2949. //
  2950. if (pSendContextLast)
  2951. {
  2952. //
  2953. // Do some sanity checks!
  2954. //
  2955. ASSERT (PreferredTrailTime >= pSendContextLast->SendStartTime);
  2956. ASSERT (SEQ_GEQ (pSendContextLast->EndSequenceNumber,pSend->pSender->TrailingEdgeSequenceNumber));
  2957. ASSERT (SEQ_GEQ (HighestTrailSeq, pSendContextLast->StartSequenceNumber));
  2958. ASSERT (SEQ_GEQ (HighestTrailSeq, pSend->pSender->TrailingEdgeSequenceNumber));
  2959. //
  2960. // See if this send is partially in or out of the window now!
  2961. // Calculate the offset of sequences in this Send request for the
  2962. // preferred trail time
  2963. //
  2964. NumExSequencesInOldWindow = (ULONG) (SEQ_TYPE) (((PreferredTrailTime-pSendContextLast->SendStartTime)*
  2965. BASIC_TIMER_GRANULARITY_IN_MSECS * pSend->pSender->pAddress->RateKbitsPerSec) /
  2966. (pSend->pSender->pAddress->OutIfMTU * BITS_PER_BYTE));
  2967. //
  2968. // Now, adjust this offset to the trailing edge
  2969. //
  2970. if (SEQ_GT ((pSendContextLast->StartSequenceNumber + NumExSequencesInOldWindow),
  2971. pSend->pSender->TrailingEdgeSequenceNumber))
  2972. {
  2973. NumExSequencesInOldWindow = pSendContextLast->StartSequenceNumber +
  2974. NumExSequencesInOldWindow -
  2975. pSend->pSender->TrailingEdgeSequenceNumber;
  2976. }
  2977. else
  2978. {
  2979. ASSERT (pSend->pSender->TrailingEdgeSequenceNumber ==
  2980. (pSendContextLast->StartSequenceNumber + NumExSequencesInOldWindow));
  2981. NumExSequencesInOldWindow = 0;
  2982. }
  2983. //
  2984. // Now, limit the # sequences to advance with the window size
  2985. //
  2986. if (NumExSequencesInOldWindow > MaxSequencesToAdvance)
  2987. {
  2988. NumExSequencesInOldWindow = MaxSequencesToAdvance;
  2989. }
  2990. //
  2991. // Finally, see if we need to limit the advance based on the RData pending requests
  2992. //
  2993. if (SEQ_GT (HighestTrailSeq, (pSend->pSender->TrailingEdgeSequenceNumber +
  2994. NumExSequencesInOldWindow)))
  2995. {
  2996. HighestTrailSeq = (SEQ_TYPE) (pSend->pSender->TrailingEdgeSequenceNumber + NumExSequencesInOldWindow);
  2997. }
  2998. else if (SEQ_GEQ (HighestTrailSeq, pSend->pSender->TrailingEdgeSequenceNumber))
  2999. {
  3000. //
  3001. // We are limited by the pending RData
  3002. // So, recalculate the PreferredTrailTime (to set the actual trail time)!
  3003. //
  3004. NumExSequencesInOldWindow = (ULONG) (SEQ_TYPE) (HighestTrailSeq - pSend->pSender->TrailingEdgeSequenceNumber);
  3005. PreferredTrailTime = (NumExSequencesInOldWindow * pSend->pSender->pAddress->OutIfMTU * BITS_PER_BYTE) /
  3006. (pSend->pSender->pAddress->RateKbitsPerSec * BASIC_TIMER_GRANULARITY_IN_MSECS);
  3007. PreferredTrailTime += pSend->pSender->TrailingEdgeTime;
  3008. }
  3009. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "AdvanceWindow",
  3010. "LastSend: NumExSeq=<%d>, HighestTrailSeq=<%d>, PreferredTrailTime=<%d:%d>\n",
  3011. (ULONG) NumExSequencesInOldWindow, (ULONG) HighestTrailSeq, PreferredTrailTime);
  3012. if (SEQ_GT (HighestTrailSeq, pSendContextLast->EndSequenceNumber) &&
  3013. (!pSendContextLast->BytesLeftToPacketize))
  3014. {
  3015. //
  3016. // We can drop this whole send since it is outside of our window
  3017. // Set the new trailing edge based on whether we have a following
  3018. // send or not!
  3019. //
  3020. if ((pSendContext1) &&
  3021. (pSendContext1 != pSendContextLast))
  3022. {
  3023. //
  3024. // Readjust the trailing time to the next send
  3025. //
  3026. PreferredTrailTime = pSendContext1->SendStartTime;
  3027. }
  3028. HighestTrailSeq = pSendContextLast->EndSequenceNumber + 1;
  3029. // Remove this send and free it!
  3030. ASSERT ((!pSendContextLast->pMessage2Request) && (!pSendContextLast->pIrp));
  3031. RemoveEntryList (&pSendContextLast->Linkage);
  3032. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside,pSendContextLast);
  3033. }
  3034. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "AdvanceWindow",
  3035. "Window Adv: NumSeq=<%d>, TrailSeqNum=<%d>==><%d>, TrailTime=<%d:%d>==><%d:%d>\n",
  3036. (ULONG) NumExSequencesInOldWindow, (ULONG) pSend->pSender->TrailingGroupSequenceNumber,
  3037. (ULONG) HighestTrailSeq, pSend->pSender->TrailingEdgeTime, PreferredTrailTime);
  3038. //
  3039. // Now, adjust the buffer settings
  3040. //
  3041. ASSERT (SEQ_GEQ (HighestTrailSeq, pSend->pSender->TrailingEdgeSequenceNumber));
  3042. NumExSequencesInOldWindow = (ULONG) (SEQ_TYPE) (HighestTrailSeq - pSend->pSender->TrailingEdgeSequenceNumber);
  3043. pSend->pSender->BufferSizeAvailable += (NumExSequencesInOldWindow * pSend->pSender->PacketBufferSize);
  3044. ASSERT (pSend->pSender->BufferSizeAvailable <= pSend->pSender->MaxDataFileSize);
  3045. pSend->pSender->TrailingWindowOffset += (NumExSequencesInOldWindow * pSend->pSender->PacketBufferSize);
  3046. if (pSend->pSender->TrailingWindowOffset >= pSend->pSender->MaxDataFileSize)
  3047. {
  3048. // Wrap around case!
  3049. pSend->pSender->TrailingWindowOffset -= pSend->pSender->MaxDataFileSize;
  3050. }
  3051. ASSERT (pSend->pSender->TrailingWindowOffset < pSend->pSender->MaxDataFileSize);
  3052. pSend->pSender->TrailingEdgeSequenceNumber = HighestTrailSeq;
  3053. pSend->pSender->TrailingGroupSequenceNumber = (HighestTrailSeq+pSend->FECGroupSize-1) &
  3054. ~((SEQ_TYPE) pSend->FECGroupSize-1);
  3055. pSend->pSender->TrailingEdgeTime = PreferredTrailTime;
  3056. } // else nothing to advance!
  3057. }
  3058. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "AdvanceWindow",
  3059. "Transmit Window Range=[%d, %d], TimerTC=[%d:%d]\n",
  3060. (ULONG) pSend->pSender->TrailingEdgeSequenceNumber,
  3061. (ULONG) (pSend->pSender->NextODataSequenceNumber-1),
  3062. pSend->pSender->TimerTickCount);
  3063. return (NumExSequencesInOldWindow);
  3064. }
  3065. //----------------------------------------------------------------------------
  3066. BOOLEAN
  3067. CheckForTermination(
  3068. IN tSEND_SESSION *pSend,
  3069. IN PGMLockHandle *pOldIrq
  3070. )
  3071. /*++
  3072. Routine Description:
  3073. This routine is called to check and terminate the session
  3074. if necessary.
  3075. The pSend lock is held before calling this routine
  3076. Arguments:
  3077. IN pSend -- Pgm session (sender) context
  3078. Return Value:
  3079. TRUE if the send window buffer is empty, FALSE otherwise
  3080. --*/
  3081. {
  3082. LIST_ENTRY *pEntry;
  3083. LIST_ENTRY ListEntry;
  3084. tCLIENT_SEND_REQUEST *pSendContext;
  3085. tSEND_RDATA_CONTEXT *pRDataContext;
  3086. PIRP pIrp;
  3087. ULONG NumSequences;
  3088. if (!(PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_DOWN)) &&
  3089. !(PGM_VERIFY_HANDLE (pSend->pSender->pAddress, PGM_VERIFY_ADDRESS_DOWN)) &&
  3090. !(pSend->SessionFlags & PGM_SESSION_CLIENT_DISCONNECTED))
  3091. {
  3092. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_CONNECT, "CheckForTermination",
  3093. "Session for pSend=<%p> does not need to be terminated\n", pSend);
  3094. return (FALSE);
  3095. }
  3096. //
  3097. // See if we have processed the disconnect for the first time yet
  3098. //
  3099. if (!(pSend->SessionFlags & PGM_SESSION_DISCONNECT_INDICATED))
  3100. {
  3101. PgmLog (PGM_LOG_INFORM_STATUS, DBG_CONNECT, "CheckForTermination",
  3102. "Session is going down!, Packets remaining=<%d>\n", pSend->pSender->NumPacketsRemaining);
  3103. pSend->SessionFlags |= PGM_SESSION_DISCONNECT_INDICATED;
  3104. //
  3105. // We have to set the FIN on the Data as well as SPM packets.
  3106. // Thus, there are 2 situations -- either we have finished sending
  3107. // all the Data packets, or we are still in the midst of sending
  3108. //
  3109. // If there are no more sends pending, we will have to
  3110. // modify the last packet ourselves to set the FIN option
  3111. //
  3112. if (!IsListEmpty (&pSend->pSender->PendingSends))
  3113. {
  3114. PgmLog (PGM_LOG_INFORM_STATUS, DBG_CONNECT, "CheckForTermination",
  3115. "Send pending on list -- setting bLastSend for FIN on last Send\n");
  3116. pSendContext = CONTAINING_RECORD (pSend->pSender->PendingSends.Blink, tCLIENT_SEND_REQUEST,Linkage);
  3117. //
  3118. // We will just set a flag here, so that when the last packet
  3119. // is packetized, the FIN flags are set
  3120. //
  3121. pSendContext->bLastSend = TRUE;
  3122. }
  3123. else if (pSend->pSender->NumODataRequestsPending)
  3124. {
  3125. PgmLog (PGM_LOG_INFORM_STATUS, DBG_CONNECT, "CheckForTermination",
  3126. "Last Send in progress -- setting bLastSend for FIN on this Send\n");
  3127. //
  3128. // If have already packetized the last send, but have not yet
  3129. // sent it out, then PgmSendNextOData will put the FIN in the data packet
  3130. // otherwise, if we have not yet packetized the packet, then we will set the
  3131. // FIN option while preparing the last packet
  3132. //
  3133. pSendContext = CONTAINING_RECORD (pSend->pSender->PendingPacketizedSends.Blink, tCLIENT_SEND_REQUEST,Linkage);
  3134. pSendContext->bLastSend = TRUE;
  3135. }
  3136. else
  3137. {
  3138. PgmLog (PGM_LOG_INFORM_STATUS, DBG_CONNECT, "CheckForTermination",
  3139. "No Sends in progress -- setting FIN for next SPM\n");
  3140. //
  3141. // We have finished packetizing and sending all the packets,
  3142. // so set the FIN flag on the SPMs and also modify the last
  3143. // RData packet (if still in the window) for the FIN -- this
  3144. // will be done when the next RData packet is sent out
  3145. //
  3146. if (pSend->SessionFlags & PGM_SESSION_SENDS_CANCELLED)
  3147. {
  3148. pSend->pSender->SpmOptions &= ~PGM_OPTION_FLAG_FIN;
  3149. pSend->pSender->SpmOptions |= PGM_OPTION_FLAG_RST;
  3150. }
  3151. else
  3152. {
  3153. pSend->pSender->SpmOptions &= ~PGM_OPTION_FLAG_RST;
  3154. pSend->pSender->SpmOptions |= PGM_OPTION_FLAG_FIN;
  3155. }
  3156. //
  3157. // We also need to send an SPM immediately
  3158. //
  3159. pSend->pSender->CurrentSPMTimeout = pSend->pSender->AmbientSPMTimeout;
  3160. pSend->SessionFlags |= PGM_SESSION_FLAG_SEND_AMBIENT_SPM;
  3161. }
  3162. return (FALSE);
  3163. }
  3164. //
  3165. // If we have a (graceful) disconnect Irp to complete, we should complete
  3166. // it if we have timed out, or are ready to do so now
  3167. //
  3168. if ((pIrp = pSend->pIrpDisconnect) && // Disconnect Irp pending
  3169. (((pSend->pSender->DisconnectTimeInTicks) && (pSend->pSender->TimerTickCount >
  3170. pSend->pSender->DisconnectTimeInTicks)) ||
  3171. ((IsListEmpty (&pSend->pSender->PendingSends)) && // No Unpacketized Sends pending
  3172. (IsListEmpty (&pSend->pSender->PendingPacketizedSends)) && // No Packetized sends pending
  3173. (IsListEmpty (&pSend->pSender->PendingRDataRequests)) && // No Pending RData requests
  3174. (IsListEmpty (&pSend->pSender->CompletedSendsInWindow)) && // Window is Empty
  3175. (pSend->pSender->SpmOptions & (PGM_OPTION_FLAG_FIN | // FIN | RST | RST_N set on SPMs
  3176. PGM_OPTION_FLAG_RST |
  3177. PGM_OPTION_FLAG_RST_N)) &&
  3178. !(pSend->SessionFlags & PGM_SESSION_FLAG_SEND_AMBIENT_SPM)))) // No Ambient Spm pending
  3179. {
  3180. pSend->pIrpDisconnect = NULL;
  3181. PgmUnlock (pSend, *pOldIrq);
  3182. PgmLog (PGM_LOG_INFORM_STATUS, DBG_CONNECT, "CheckForTermination",
  3183. "Completing Graceful disconnect pIrp=<%p>\n", pIrp);
  3184. PgmIoComplete (pIrp, STATUS_SUCCESS, 0);
  3185. PgmLock (pSend, *pOldIrq);
  3186. return (FALSE);
  3187. }
  3188. //
  3189. // Do the final cleanup only if the handles have been closed
  3190. // or the disconnect has timed out
  3191. //
  3192. if (!(PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_DOWN)) &&
  3193. !(PGM_VERIFY_HANDLE (pSend->pSender->pAddress, PGM_VERIFY_ADDRESS_DOWN)) &&
  3194. ((!pSend->pSender->DisconnectTimeInTicks) || (pSend->pSender->TimerTickCount <
  3195. pSend->pSender->DisconnectTimeInTicks)))
  3196. {
  3197. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_CONNECT, "CheckForTermination",
  3198. "Handles have not yet been closed for pSend=<%p>, TC=<%x:%x>, DisconnectTime=<%x:%x>\n",
  3199. pSend, pSend->pSender->TimerTickCount, pSend->pSender->DisconnectTimeInTicks);
  3200. return (FALSE);
  3201. }
  3202. // *****************************************************************
  3203. // We will reach here only if we need to cleanup ASAP
  3204. // *****************************************************************
  3205. //
  3206. // First, cleanup all handled RData requests (which have completed)
  3207. //
  3208. pEntry = &pSend->pSender->HandledRDataRequests;
  3209. while ((pEntry = pEntry->Flink) != &pSend->pSender->HandledRDataRequests)
  3210. {
  3211. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  3212. ASSERT (!pRDataContext->NumNaks);
  3213. if (!pRDataContext->NumPacketsInTransport)
  3214. {
  3215. pEntry = pEntry->Blink; // Set this because this pEntry will not be valid any more!
  3216. RemoveEntryList (&pRDataContext->Linkage);
  3217. PgmFreeMem (pRDataContext);
  3218. }
  3219. }
  3220. //
  3221. // Now, remove all pending RData requests (since this is an Abort scenario)
  3222. // If they have any sends pending, we will put them on the handled
  3223. // list now and cleanup later
  3224. //
  3225. pEntry = &pSend->pSender->PendingRDataRequests;
  3226. while ((pEntry = pEntry->Flink) != &pSend->pSender->PendingRDataRequests)
  3227. {
  3228. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  3229. pEntry = pEntry->Blink; // Set this because this pEntry will not be valid any more!
  3230. ASSERT (pRDataContext->NumNaks);
  3231. pRDataContext->NumNaks = 0;
  3232. RemoveEntryList (&pRDataContext->Linkage);
  3233. pSend->pSender->NumRDataRequestsPending--;
  3234. if (pRDataContext->NumPacketsInTransport)
  3235. {
  3236. InsertTailList (&pSend->pSender->HandledRDataRequests, &pRDataContext->Linkage);
  3237. }
  3238. else
  3239. {
  3240. PgmFreeMem (pRDataContext);
  3241. }
  3242. }
  3243. //
  3244. // Now, Cancel and Complete all the send requests which are pending
  3245. //
  3246. InitializeListHead (&ListEntry);
  3247. PgmCancelAllSends (pSend, &ListEntry, NULL);
  3248. while (!IsListEmpty (&ListEntry))
  3249. {
  3250. pEntry = RemoveHeadList (&ListEntry);
  3251. pSendContext = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  3252. ASSERT (!pSendContext->pMessage2Request);
  3253. PgmUnlock (pSend, *pOldIrq);
  3254. if (pSendContext->pIrpToComplete)
  3255. {
  3256. ASSERT (pSendContext->pIrpToComplete == pSendContext->pIrp);
  3257. PgmIoComplete (pSendContext->pIrpToComplete, STATUS_CANCELLED, 0);
  3258. }
  3259. else
  3260. {
  3261. ASSERT (pSendContext->pIrp);
  3262. }
  3263. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  3264. PgmLock (pSend, *pOldIrq);
  3265. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext);
  3266. }
  3267. //
  3268. // Verify that at least 1 SPM with the FIN or RST or RST_N flag
  3269. // has been sent
  3270. //
  3271. if (!(pSend->pSender->SpmOptions & (PGM_OPTION_FLAG_FIN |
  3272. PGM_OPTION_FLAG_RST |
  3273. PGM_OPTION_FLAG_RST_N)))
  3274. {
  3275. if (pSend->SessionFlags & PGM_SESSION_SENDS_CANCELLED)
  3276. {
  3277. pSend->pSender->SpmOptions &= ~PGM_OPTION_FLAG_FIN;
  3278. pSend->pSender->SpmOptions |= PGM_OPTION_FLAG_RST;
  3279. }
  3280. else
  3281. {
  3282. pSend->pSender->SpmOptions &= ~PGM_OPTION_FLAG_RST;
  3283. pSend->pSender->SpmOptions |= PGM_OPTION_FLAG_FIN;
  3284. }
  3285. pSend->SessionFlags |= PGM_SESSION_FLAG_SEND_AMBIENT_SPM;
  3286. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_CONNECT, "CheckForTermination",
  3287. "SPM with FIN|RST|RST_N has not yet been sent for pSend=<%p>\n", pSend);
  3288. return (FALSE);
  3289. }
  3290. //
  3291. // Verify that there are no SPMs pending
  3292. //
  3293. if (pSend->SessionFlags & PGM_SESSION_FLAG_SEND_AMBIENT_SPM)
  3294. {
  3295. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_CONNECT, "CheckForTermination",
  3296. "Cannot cleanup pSend=<%p> since we have Ambient SPM pending!\n", pSend);
  3297. return (FALSE);
  3298. }
  3299. //
  3300. // Verify that we do not have any completions pending also since
  3301. // Ip would need to reference the data buffer otherwise
  3302. //
  3303. while (!IsListEmpty (&pSend->pSender->CompletedSendsInWindow))
  3304. {
  3305. pSendContext = CONTAINING_RECORD (pSend->pSender->CompletedSendsInWindow.Flink, tCLIENT_SEND_REQUEST, Linkage);
  3306. if (pSendContext->NumSendsPending)
  3307. {
  3308. PgmLog (PGM_LOG_INFORM_STATUS, DBG_SEND, "CheckForTermination",
  3309. "Session has terminated, but cannot continue cleanup since Sends are still pending!\n");
  3310. break;
  3311. }
  3312. //
  3313. // Now, set the buffer settings
  3314. //
  3315. ASSERT (SEQ_GEQ (pSend->pSender->TrailingEdgeSequenceNumber, pSendContext->StartSequenceNumber) &&
  3316. SEQ_LEQ (pSend->pSender->TrailingEdgeSequenceNumber, pSendContext->EndSequenceNumber));
  3317. NumSequences = (ULONG) (SEQ_TYPE) (pSendContext->EndSequenceNumber-pSend->pSender->TrailingEdgeSequenceNumber) +1;
  3318. pSend->pSender->BufferSizeAvailable += (NumSequences * pSend->pSender->PacketBufferSize);
  3319. ASSERT (pSend->pSender->BufferSizeAvailable <= pSend->pSender->MaxDataFileSize);
  3320. pSend->pSender->TrailingWindowOffset += (NumSequences * pSend->pSender->PacketBufferSize);
  3321. if (pSend->pSender->TrailingWindowOffset >= pSend->pSender->MaxDataFileSize)
  3322. {
  3323. // Wrap around case!
  3324. pSend->pSender->TrailingWindowOffset -= pSend->pSender->MaxDataFileSize;
  3325. }
  3326. ASSERT (pSend->pSender->TrailingWindowOffset < pSend->pSender->MaxDataFileSize);
  3327. pSend->pSender->TrailingEdgeSequenceNumber += (SEQ_TYPE) NumSequences;
  3328. ASSERT ((!pSendContext->pMessage2Request) && (!pSendContext->pIrp));
  3329. RemoveEntryList (&pSendContext->Linkage);
  3330. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext);
  3331. }
  3332. //
  3333. // If any sends are pending, return False
  3334. //
  3335. if ((pSend->pIrpDisconnect) ||
  3336. !(IsListEmpty (&pSend->pSender->CompletedSendsInWindow)) ||
  3337. !(IsListEmpty (&pSend->pSender->PendingSends)) ||
  3338. !(IsListEmpty (&pSend->pSender->PendingPacketizedSends)) ||
  3339. !(IsListEmpty (&pSend->pSender->PendingRDataRequests)) ||
  3340. !(IsListEmpty (&pSend->pSender->HandledRDataRequests)))
  3341. {
  3342. PgmLog (PGM_LOG_INFORM_STATUS, DBG_SEND, "CheckForTermination",
  3343. "Cannot cleanup completely since transmit Window=[%d--%d] still has pending Sends!\n",
  3344. (ULONG) pSend->pSender->TrailingEdgeSequenceNumber,
  3345. (ULONG) (pSend->pSender->NextODataSequenceNumber-1));
  3346. return (FALSE);
  3347. }
  3348. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "CheckForTermination",
  3349. "Transmit Window has no pending Sends! TimerTC=[%d:%d]\n", pSend->pSender->TimerTickCount);
  3350. ASSERT (!pSend->pIrpDisconnect);
  3351. return (TRUE);
  3352. }
  3353. //----------------------------------------------------------------------------
  3354. BOOLEAN
  3355. SendNextPacket(
  3356. IN tSEND_SESSION *pSend
  3357. )
  3358. /*++
  3359. Routine Description:
  3360. This routine is queued by the timer to send Data/Spm packets
  3361. based on available throughput
  3362. Arguments:
  3363. IN pSend -- Pgm session (sender) context
  3364. IN Unused1
  3365. IN Unused2
  3366. Return Value:
  3367. NONE
  3368. --*/
  3369. {
  3370. ULONG BytesSent;
  3371. ULONG NumSequences;
  3372. PGMLockHandle OldIrq;
  3373. BOOLEAN fTerminateSession = FALSE;
  3374. LIST_ENTRY *pEntry;
  3375. tSEND_RDATA_CONTEXT *pRDataContext, *pRDataToSend;
  3376. BOOLEAN fSendRData = TRUE;
  3377. PgmLock (pSend, OldIrq);
  3378. //
  3379. // pSend->pSender->CurrentBytesSendable applies to OData, RData and SPMs only
  3380. //
  3381. while (pSend->pSender->CurrentBytesSendable >= pSend->pSender->pAddress->OutIfMTU)
  3382. {
  3383. BytesSent = 0;
  3384. //
  3385. // See if we need to send any Ambient SPMs
  3386. //
  3387. if ((pSend->SessionFlags & PGM_SESSION_FLAG_SEND_AMBIENT_SPM) &&
  3388. ((pSend->pSender->PacketsSentSinceLastSpm > MAX_DATA_PACKETS_BEFORE_SPM) ||
  3389. (pSend->pSender->CurrentSPMTimeout >= pSend->pSender->AmbientSPMTimeout)))
  3390. {
  3391. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3392. "Send Ambient SPM, TC=[%d:%d], BS=<%d>\n",
  3393. pSend->pSender->TimerTickCount, pSend->pSender->CurrentBytesSendable);
  3394. //
  3395. // Some data packet was sent recently, so we are in Ambient SPM mode
  3396. //
  3397. PgmSendSpm (pSend, &OldIrq, &BytesSent);
  3398. pSend->pSender->CurrentSPMTimeout = 0; // Reset the SPM timeout
  3399. pSend->pSender->HeartbeatSPMTimeout = pSend->pSender->InitialHeartbeatSPMTimeout;
  3400. pSend->SessionFlags &= ~PGM_SESSION_FLAG_SEND_AMBIENT_SPM;
  3401. pSend->pSender->PacketsSentSinceLastSpm = 0;
  3402. }
  3403. //
  3404. // Otherwise see if we need to send any Heartbeat SPMs
  3405. //
  3406. else if ((!(pSend->SessionFlags & PGM_SESSION_FLAG_SEND_AMBIENT_SPM)) &&
  3407. (pSend->pSender->CurrentSPMTimeout >= pSend->pSender->HeartbeatSPMTimeout))
  3408. {
  3409. //
  3410. // No data packet was sent recently, so we need to send a Heartbeat SPM
  3411. //
  3412. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3413. "Send Heartbeat SPM, TC=[%d:%d], BS=<%d>\n",
  3414. pSend->pSender->TimerTickCount, pSend->pSender->CurrentBytesSendable);
  3415. //
  3416. // (Send Heartbeat SPM Packet)
  3417. //
  3418. PgmSendSpm (pSend, &OldIrq, &BytesSent);
  3419. pSend->pSender->CurrentSPMTimeout = 0; // Reset the SPM timeout
  3420. pSend->pSender->HeartbeatSPMTimeout *= 2;
  3421. if (pSend->pSender->HeartbeatSPMTimeout > pSend->pSender->MaxHeartbeatSPMTimeout)
  3422. {
  3423. pSend->pSender->HeartbeatSPMTimeout = pSend->pSender->MaxHeartbeatSPMTimeout;
  3424. }
  3425. pSend->pSender->PacketsSentSinceLastSpm = 0;
  3426. }
  3427. //
  3428. // Next, see if we need to send any RData
  3429. //
  3430. else if ((pSend->pSender->NumRDataRequestsPending) || (pSend->pSender->NumODataRequestsPending))
  3431. {
  3432. //
  3433. // See if we need to send an RData packet now
  3434. //
  3435. pRDataToSend = NULL;
  3436. if ((pSend->pSender->NumRDataRequestsPending) &&
  3437. (fSendRData || !pSend->pSender->NumODataRequestsPending))
  3438. {
  3439. pEntry = &pSend->pSender->PendingRDataRequests;
  3440. while ((pEntry = pEntry->Flink) != &pSend->pSender->PendingRDataRequests)
  3441. {
  3442. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  3443. if (pSend->pSender->TimerTickCount >= pRDataContext->EarliestRDataSendTime)
  3444. {
  3445. pRDataToSend = pRDataContext;
  3446. break;
  3447. }
  3448. }
  3449. if (pRDataToSend)
  3450. {
  3451. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3452. "Send RData[%d] -- TC=[%d:%d], BS=<%d>, MTU=<%d>\n",
  3453. pRDataContext->RDataSequenceNumber, pSend->pSender->TimerTickCount,
  3454. pSend->pSender->CurrentBytesSendable, pSend->pSender->pAddress->OutIfMTU);
  3455. PgmSendRData (pSend, pRDataToSend, &OldIrq, &BytesSent);
  3456. }
  3457. else if (!pSend->pSender->NumODataRequestsPending)
  3458. {
  3459. //
  3460. // Since we don't have any OData pending, send the next RData anyway!
  3461. //
  3462. pRDataToSend = CONTAINING_RECORD (pSend->pSender->PendingRDataRequests.Flink, tSEND_RDATA_CONTEXT, Linkage);
  3463. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3464. "No OData! Send RData[%d] -- TC=[%d:%d], BS=<%d>, MTU=<%d>\n",
  3465. pRDataContext->RDataSequenceNumber, pSend->pSender->TimerTickCount,
  3466. pSend->pSender->CurrentBytesSendable, pSend->pSender->pAddress->OutIfMTU);
  3467. PgmSendRData (pSend, pRDataToSend, &OldIrq, &BytesSent);
  3468. }
  3469. else
  3470. {
  3471. //
  3472. // We will not attempt to send any more RData at this time
  3473. //
  3474. fSendRData = FALSE;
  3475. }
  3476. }
  3477. if ((!pRDataToSend) &&
  3478. pSend->pSender->NumODataRequestsPending)
  3479. {
  3480. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3481. "Send OData -- TC=[%d:%d], BS=<%d>, MTU=<%d>\n",
  3482. pSend->pSender->TimerTickCount, pSend->pSender->CurrentBytesSendable,
  3483. pSend->pSender->pAddress->OutIfMTU);
  3484. //
  3485. // Send OData
  3486. //
  3487. PgmSendNextOData (pSend, &OldIrq, &BytesSent);
  3488. }
  3489. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3490. "Sent <%d> Data bytes\n", BytesSent);
  3491. if (BytesSent == 0)
  3492. {
  3493. //
  3494. // We may not have enough buffer space to packetize and send
  3495. // more data, or we have no data to send at this time, so just
  3496. // break out and see if we can advance the trailing window!
  3497. //
  3498. if (pSend->pSender->CurrentBytesSendable >
  3499. (NUM_LEAKY_BUCKETS * pSend->pSender->IncrementBytesOnSendTimeout))
  3500. {
  3501. pSend->pSender->CurrentBytesSendable = NUM_LEAKY_BUCKETS *
  3502. pSend->pSender->IncrementBytesOnSendTimeout;
  3503. }
  3504. break;
  3505. }
  3506. pSend->SessionFlags |= PGM_SESSION_FLAG_SEND_AMBIENT_SPM;
  3507. pSend->pSender->PacketsSentSinceLastSpm++;
  3508. }
  3509. //
  3510. // We do not have any more packets to send, so reset
  3511. // BytesSendable so that we don't exceed the rate on
  3512. // the next send
  3513. //
  3514. else
  3515. {
  3516. if (pSend->pSender->CurrentBytesSendable >
  3517. (NUM_LEAKY_BUCKETS * pSend->pSender->IncrementBytesOnSendTimeout))
  3518. {
  3519. pSend->pSender->CurrentBytesSendable = NUM_LEAKY_BUCKETS *
  3520. pSend->pSender->IncrementBytesOnSendTimeout;
  3521. }
  3522. break;
  3523. }
  3524. pSend->TotalBytes += BytesSent;
  3525. pSend->pSender->CurrentBytesSendable -= BytesSent;
  3526. } // while (CurrentBytesSendable >= pSend->pSender->pAddress->OutIfMTU)
  3527. //
  3528. // See if we need to scavenge completed RData requests
  3529. //
  3530. pEntry = &pSend->pSender->HandledRDataRequests;
  3531. while ((pEntry = pEntry->Flink) != &pSend->pSender->HandledRDataRequests)
  3532. {
  3533. pRDataContext = CONTAINING_RECORD (pEntry, tSEND_RDATA_CONTEXT, Linkage);
  3534. if ((pRDataContext->CleanupTime) &&
  3535. (pSend->pSender->TimerTickCount > pRDataContext->CleanupTime))
  3536. {
  3537. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "DelayedSendNextPacket",
  3538. "Removing lingering RData for SeqNum=<%d>\n", (ULONG) pRDataContext->RDataSequenceNumber);
  3539. pEntry = pEntry->Blink; // Set this because this pEntry will not be valid any more!
  3540. RemoveEntryList (&pRDataContext->Linkage);
  3541. PgmFreeMem (pRDataContext);
  3542. }
  3543. }
  3544. //
  3545. // See if we need to increment the Trailing Window -- returns number of Sequences advanced
  3546. //
  3547. NumSequences = AdvanceWindow (pSend);
  3548. //
  3549. // Now check if we need to terminate this session
  3550. //
  3551. fTerminateSession = CheckForTermination (pSend, &OldIrq);
  3552. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "DelayedSendNextPacket",
  3553. "Sent <%d> total bytes, fTerminateSession=<%x>\n", pSend->TotalBytes, fTerminateSession);
  3554. //
  3555. // Clear the WorkerRunning flag so that the next Worker
  3556. // routine can be queued
  3557. //
  3558. pSend->SessionFlags &= ~PGM_SESSION_FLAG_WORKER_RUNNING;
  3559. PgmUnlock (pSend, OldIrq);
  3560. return (fTerminateSession);
  3561. }
  3562. //----------------------------------------------------------------------------
  3563. VOID
  3564. SendSessionTimeout(
  3565. IN PKDPC Dpc,
  3566. IN PVOID DeferredContext,
  3567. IN PVOID SystemArg1,
  3568. IN PVOID SystemArg2
  3569. )
  3570. /*++
  3571. Routine Description:
  3572. This routine is the timout that gets called every BASIC_TIMER_GRANULARITY_IN_MSECS
  3573. to schedule the next Send request
  3574. Arguments:
  3575. IN Dpc
  3576. IN DeferredContext -- Our context for this timer
  3577. IN SystemArg1
  3578. IN SystemArg2
  3579. Return Value:
  3580. NONE
  3581. --*/
  3582. {
  3583. NTSTATUS status;
  3584. tADDRESS_CONTEXT *pAddress;
  3585. PGMLockHandle OldIrq;
  3586. tSEND_SESSION *pSend = (tSEND_SESSION *) DeferredContext;
  3587. LARGE_INTEGER Now, Frequency;
  3588. LARGE_INTEGER DeltaTime, GranularTimeElapsed, TimeoutGranularity;
  3589. ULONG NumTimeouts;
  3590. SEQ_TYPE NumSequencesInWindow;
  3591. Now = KeQueryPerformanceCounter (&Frequency);
  3592. PgmLock (pSend, OldIrq);
  3593. //
  3594. // First check if we have been told to stop the timer
  3595. //
  3596. if (pSend->SessionFlags & PGM_SESSION_FLAG_STOP_TIMER)
  3597. {
  3598. PgmLog (PGM_LOG_INFORM_STATUS, DBG_SEND, "SendSessionTimeout",
  3599. "Session has terminated -- will deref and not restart timer!\n");
  3600. //
  3601. // Deref for the timer reference
  3602. //
  3603. pAddress = pSend->pSender->pAddress;
  3604. pSend->pSender->pAddress = NULL;
  3605. PgmUnlock (pSend, OldIrq);
  3606. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_TIMER_RUNNING);
  3607. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SEND_IN_PROGRESS);
  3608. return;
  3609. }
  3610. DeltaTime.QuadPart = Now.QuadPart - pSend->pSender->LastTimeout.QuadPart;
  3611. TimeoutGranularity.QuadPart = pSend->pSender->TimeoutGranularity.QuadPart;
  3612. for (GranularTimeElapsed.QuadPart = 0, NumTimeouts = 0;
  3613. DeltaTime.QuadPart > TimeoutGranularity.QuadPart;
  3614. NumTimeouts++)
  3615. {
  3616. GranularTimeElapsed.QuadPart += TimeoutGranularity.QuadPart;
  3617. DeltaTime.QuadPart -= TimeoutGranularity.QuadPart;
  3618. }
  3619. if (NumTimeouts)
  3620. {
  3621. pSend->RateCalcTimeout += NumTimeouts;
  3622. if (pSend->RateCalcTimeout >=
  3623. (INTERNAL_RATE_CALCULATION_FREQUENCY/BASIC_TIMER_GRANULARITY_IN_MSECS))
  3624. {
  3625. pSend->RateKBitsPerSecOverall = (pSend->TotalBytes << LOG2_BITS_PER_BYTE) /
  3626. (pSend->pSender->TimerTickCount * BASIC_TIMER_GRANULARITY_IN_MSECS);
  3627. pSend->RateKBitsPerSecLast = (pSend->TotalBytes - pSend->TotalBytesAtLastInterval) >>
  3628. (LOG2_INTERNAL_RATE_CALCULATION_FREQUENCY - LOG2_BITS_PER_BYTE);
  3629. pSend->DataBytesAtLastInterval = pSend->DataBytes;
  3630. pSend->TotalBytesAtLastInterval = pSend->TotalBytes;
  3631. pSend->RateCalcTimeout = 0;
  3632. }
  3633. pSend->pSender->LastTimeout.QuadPart += GranularTimeElapsed.QuadPart;
  3634. //
  3635. // Increment the absolute timer, and check for overflow
  3636. //
  3637. pSend->pSender->TimerTickCount += NumTimeouts;
  3638. //
  3639. // If the SPMTimeout value is less than the HeartbeatTimeout, increment it
  3640. //
  3641. if (pSend->pSender->CurrentSPMTimeout <= pSend->pSender->HeartbeatSPMTimeout)
  3642. {
  3643. pSend->pSender->CurrentSPMTimeout += NumTimeouts;
  3644. }
  3645. //
  3646. // See if we can send anything
  3647. //
  3648. ASSERT (pSend->pSender->CurrentTimeoutCount);
  3649. ASSERT (pSend->pSender->SendTimeoutCount);
  3650. if (pSend->pSender->CurrentTimeoutCount > NumTimeouts)
  3651. {
  3652. pSend->pSender->CurrentTimeoutCount -= NumTimeouts;
  3653. }
  3654. else
  3655. {
  3656. //
  3657. // We got here because NumTimeouts >= pSend->pSender->CurrentTimeoutCount
  3658. //
  3659. pSend->pSender->CurrentBytesSendable += (ULONG) pSend->pSender->IncrementBytesOnSendTimeout;
  3660. if (NumTimeouts != pSend->pSender->CurrentTimeoutCount)
  3661. {
  3662. if (1 == pSend->pSender->SendTimeoutCount)
  3663. {
  3664. pSend->pSender->CurrentBytesSendable += (ULONG) ((NumTimeouts - pSend->pSender->CurrentTimeoutCount)
  3665. * pSend->pSender->IncrementBytesOnSendTimeout);
  3666. }
  3667. else
  3668. {
  3669. //
  3670. // This path will get taken on a slow receiver when the timer
  3671. // fires at a lower granularity than that requested
  3672. //
  3673. pSend->pSender->CurrentBytesSendable += (ULONG) (((NumTimeouts - pSend->pSender->CurrentTimeoutCount)
  3674. * pSend->pSender->IncrementBytesOnSendTimeout) /
  3675. pSend->pSender->SendTimeoutCount);
  3676. }
  3677. }
  3678. pSend->pSender->CurrentTimeoutCount = pSend->pSender->SendTimeoutCount;
  3679. //
  3680. // Send a synchronization event to the sender thread to
  3681. // send the next available data
  3682. //
  3683. KeSetEvent (&pSend->pSender->SendEvent, 0, FALSE);
  3684. }
  3685. }
  3686. PgmUnlock (pSend, OldIrq);
  3687. //
  3688. // Now, restart the timer
  3689. //
  3690. PgmInitTimer (&pSend->SessionTimer);
  3691. PgmStartTimer (&pSend->SessionTimer, BASIC_TIMER_GRANULARITY_IN_MSECS, SendSessionTimeout, pSend);
  3692. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_SEND, "SendSessionTimeout",
  3693. "TickCount=<%d:%d>, CurrentTimeoutCount=<%d:%d>, CurrentSPMTimeout=<%d:%d>, Worker %srunning\n",
  3694. pSend->pSender->TimerTickCount, pSend->pSender->CurrentTimeoutCount,
  3695. pSend->pSender->CurrentSPMTimeout,
  3696. ((pSend->SessionFlags & PGM_SESSION_FLAG_WORKER_RUNNING) ? "" : "NOT "));
  3697. }
  3698. //----------------------------------------------------------------------------
  3699. VOID
  3700. SenderWorkerThread(
  3701. IN tSEND_SESSION *pSend
  3702. )
  3703. {
  3704. BOOLEAN fTerminateSends;
  3705. PGMLockHandle OldIrq;
  3706. NTSTATUS status;
  3707. do
  3708. {
  3709. status = KeWaitForSingleObject (&pSend->pSender->SendEvent, // Object to wait on.
  3710. Executive, // Reason for waiting
  3711. KernelMode, // Processor mode
  3712. FALSE, // Alertable
  3713. NULL); // Timeout
  3714. ASSERT (NT_SUCCESS (status));
  3715. fTerminateSends = SendNextPacket (pSend);
  3716. }
  3717. while (!fTerminateSends);
  3718. PgmLock (pSend, OldIrq);
  3719. pSend->SessionFlags |= PGM_SESSION_FLAG_STOP_TIMER; // To ensure timer does last deref and stops
  3720. PgmUnlock (pSend, OldIrq);
  3721. // PsTerminateSystemThread (STATUS_SUCCESS);
  3722. return;
  3723. }
  3724. //----------------------------------------------------------------------------
  3725. VOID
  3726. PgmCancelSendIrp(
  3727. IN PDEVICE_OBJECT DeviceContext,
  3728. IN PIRP pIrp
  3729. )
  3730. /*++
  3731. Routine Description:
  3732. This routine handles the cancelling of a Send Irp. It must release the
  3733. cancel spin lock before returning re: IoCancelIrp().
  3734. Arguments:
  3735. Return Value:
  3736. None
  3737. --*/
  3738. {
  3739. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation (pIrp);
  3740. tSEND_SESSION *pSend = (tSEND_SESSION *) pIrpSp->FileObject->FsContext;
  3741. PGMLockHandle OldIrq;
  3742. PLIST_ENTRY pEntry;
  3743. LIST_ENTRY ListEntry;
  3744. tCLIENT_SEND_REQUEST *pSendContext1;
  3745. tCLIENT_SEND_REQUEST *pSendContext2 = NULL;
  3746. ULONG NumRequests;
  3747. if (!PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_SEND))
  3748. {
  3749. IoReleaseCancelSpinLock (pIrp->CancelIrql);
  3750. PgmLog (PGM_LOG_ERROR, (DBG_SEND | DBG_ADDRESS | DBG_CONNECT), "PgmCancelSendIrp",
  3751. "pIrp=<%p> pSend=<%p>, pAddress=<%p>\n", pIrp, pSend, pSend->pAssociatedAddress);
  3752. return;
  3753. }
  3754. PgmLock (pSend, OldIrq);
  3755. //
  3756. // First, see if the Irp is on any of our lists
  3757. //
  3758. pEntry = &pSend->pSender->PendingSends;
  3759. while ((pEntry = pEntry->Flink) != &pSend->pSender->PendingSends)
  3760. {
  3761. pSendContext1 = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  3762. if (pSendContext1->pIrp == pIrp)
  3763. {
  3764. pSendContext2 = pSendContext1;
  3765. break;
  3766. }
  3767. }
  3768. if (!pSendContext2)
  3769. {
  3770. //
  3771. // Now, search the packetized list
  3772. //
  3773. pEntry = &pSend->pSender->PendingPacketizedSends;
  3774. while ((pEntry = pEntry->Flink) != &pSend->pSender->PendingPacketizedSends)
  3775. {
  3776. pSendContext1 = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  3777. if (pSendContext1->pIrp == pIrp)
  3778. {
  3779. pSendContext2 = pSendContext1;
  3780. break;
  3781. }
  3782. }
  3783. if (!pSendContext2)
  3784. {
  3785. //
  3786. // We did not find the irp -- either it was just being completed
  3787. // (or waiting for a send-complete), or the Irp was bad ?
  3788. //
  3789. PgmUnlock (pSend, OldIrq);
  3790. IoReleaseCancelSpinLock (pIrp->CancelIrql);
  3791. PgmLog (PGM_LOG_INFORM_PATH, DBG_CONNECT, "PgmCancelSendIrp",
  3792. "Did not find Cancel Irp=<%p>\n", pIrp);
  3793. return;
  3794. }
  3795. }
  3796. InitializeListHead (&ListEntry);
  3797. PgmCancelAllSends (pSend, &ListEntry, pIrp);
  3798. PgmUnlock (pSend, OldIrq);
  3799. IoReleaseCancelSpinLock (pIrp->CancelIrql);
  3800. //
  3801. // Now, complete all the sends which we removed
  3802. //
  3803. NumRequests = 0;
  3804. while (!IsListEmpty (&ListEntry))
  3805. {
  3806. pEntry = RemoveHeadList (&ListEntry);
  3807. pSendContext1 = CONTAINING_RECORD (pEntry, tCLIENT_SEND_REQUEST, Linkage);
  3808. ASSERT (!pSendContext1->pMessage2Request);
  3809. if (pSendContext1->pIrpToComplete)
  3810. {
  3811. NumRequests++;
  3812. ASSERT (pSendContext1->pIrpToComplete == pSendContext1->pIrp);
  3813. PgmIoComplete (pSendContext1->pIrpToComplete, STATUS_CANCELLED, 0);
  3814. }
  3815. else
  3816. {
  3817. ASSERT (pSendContext1->pIrp);
  3818. }
  3819. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  3820. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext1);
  3821. }
  3822. PgmLog (PGM_LOG_INFORM_PATH, DBG_CONNECT, "PgmCancelSendIrp",
  3823. "Cancelled <%d> Irps for pIrp=<%p>\n", NumRequests, pIrp);
  3824. }
  3825. //----------------------------------------------------------------------------
  3826. NTSTATUS
  3827. PgmSendRequestFromClient(
  3828. IN tPGM_DEVICE *pPgmDevice,
  3829. IN PIRP pIrp,
  3830. IN PIO_STACK_LOCATION pIrpSp
  3831. )
  3832. /*++
  3833. Routine Description:
  3834. This routine is called via dispatch by the client to post a Send pIrp
  3835. Arguments:
  3836. IN pPgmDevice -- Pgm's Device object context
  3837. IN pIrp -- Client's request Irp
  3838. IN pIrpSp -- current request's stack pointer
  3839. Return Value:
  3840. NTSTATUS - Final status of the request
  3841. --*/
  3842. {
  3843. NTSTATUS status;
  3844. PGMLockHandle OldIrq1, OldIrq2, OldIrq3, OldIrq4;
  3845. tADDRESS_CONTEXT *pAddress = NULL;
  3846. tCLIENT_SEND_REQUEST *pSendContext1;
  3847. tCLIENT_SEND_REQUEST *pSendContext2 = NULL;
  3848. ULONG BytesLeftInMessage;
  3849. tSEND_SESSION *pSend = (tSEND_SESSION *) pIrpSp->FileObject->FsContext;
  3850. PTDI_REQUEST_KERNEL_SEND pTdiRequest = (PTDI_REQUEST_KERNEL_SEND) &pIrpSp->Parameters;
  3851. KAPC_STATE ApcState;
  3852. BOOLEAN fFirstSend, fResourceAcquired, fAttached;
  3853. LARGE_INTEGER Frequency;
  3854. LIST_ENTRY ListEntry;
  3855. PgmLock (&PgmDynamicConfig, OldIrq1);
  3856. //
  3857. // Verify that the connection is valid and is associated with an address
  3858. //
  3859. if ((!PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_SEND)) ||
  3860. (!(pAddress = pSend->pAssociatedAddress)) ||
  3861. (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)) ||
  3862. (pSend->SessionFlags & (PGM_SESSION_CLIENT_DISCONNECTED | PGM_SESSION_SENDS_CANCELLED)) ||
  3863. (pAddress->Flags & PGM_ADDRESS_FLAG_INVALID_OUT_IF))
  3864. {
  3865. PgmLog (PGM_LOG_ERROR, (DBG_SEND | DBG_ADDRESS | DBG_CONNECT), "PgmSend",
  3866. "Invalid Handles pSend=<%p>, pAddress=<%p>\n", pSend, pAddress);
  3867. PgmUnlock (&PgmDynamicConfig, OldIrq1);
  3868. return (STATUS_INVALID_HANDLE);
  3869. }
  3870. if (!pSend->pSender->DestMCastIpAddress)
  3871. {
  3872. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSend",
  3873. "Destination address not specified for pSend=<%p>\n", pSend);
  3874. PgmUnlock (&PgmDynamicConfig, OldIrq1);
  3875. return (STATUS_INVALID_ADDRESS_COMPONENT);
  3876. }
  3877. if (!pTdiRequest->SendLength)
  3878. {
  3879. PgmLog (PGM_LOG_INFORM_STATUS, DBG_SEND, "PgmSend",
  3880. "pIrp=<%p> for pSend=<%p> is of length 0!\n", pIrp, pSend);
  3881. PgmUnlock (&PgmDynamicConfig, OldIrq1);
  3882. return (STATUS_SUCCESS);
  3883. }
  3884. PgmLock (pAddress, OldIrq2);
  3885. PgmLock (pSend, OldIrq3);
  3886. if (!(pSendContext1 = ExAllocateFromNPagedLookasideList (&pSend->pSender->SendContextLookaside)))
  3887. {
  3888. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSend",
  3889. "STATUS_INSUFFICIENT_RESOURCES allocating pSendContext1\n");
  3890. return (STATUS_INSUFFICIENT_RESOURCES);
  3891. }
  3892. //
  3893. // If we have more that 1 message data in this request,
  3894. // we will need another send context
  3895. //
  3896. if ((pSend->pSender->ThisSendMessageLength) && // Client has specified current message length
  3897. (BytesLeftInMessage = pSend->pSender->ThisSendMessageLength - pSend->pSender->BytesSent) &&
  3898. (BytesLeftInMessage < pTdiRequest->SendLength) && // ==> Have some extra data in this request
  3899. (!(pSendContext2 = ExAllocateFromNPagedLookasideList (&pSend->pSender->SendContextLookaside))))
  3900. {
  3901. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext1);
  3902. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSend",
  3903. "STATUS_INSUFFICIENT_RESOURCES allocating pSendContext1\n");
  3904. return (STATUS_INSUFFICIENT_RESOURCES);
  3905. }
  3906. //
  3907. //
  3908. // Zero the SendDataContext structure(s)
  3909. //
  3910. PgmZeroMemory (pSendContext1, sizeof (tCLIENT_SEND_REQUEST));
  3911. InitializeListHead (&pSendContext1->Linkage);
  3912. if (pSendContext2)
  3913. {
  3914. PgmZeroMemory (pSendContext2, sizeof (tCLIENT_SEND_REQUEST));
  3915. InitializeListHead (&pSendContext2->Linkage);
  3916. }
  3917. if (pSend->SessionFlags & PGM_SESSION_FLAG_FIRST_PACKET)
  3918. {
  3919. fFirstSend = TRUE;
  3920. }
  3921. else
  3922. {
  3923. fFirstSend = FALSE;
  3924. }
  3925. //
  3926. // Reference the Address and Connection so that they cannot go away
  3927. // while we are processing!
  3928. //
  3929. PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW, TRUE);
  3930. PgmUnlock (pSend, OldIrq3);
  3931. PgmUnlock (pAddress, OldIrq2);
  3932. PgmUnlock (&PgmDynamicConfig, OldIrq1);
  3933. if (PgmGetCurrentIrql())
  3934. {
  3935. fResourceAcquired = FALSE;
  3936. }
  3937. else
  3938. {
  3939. fResourceAcquired = TRUE;
  3940. PgmAcquireResourceExclusive (&pSend->pSender->Resource, TRUE);
  3941. }
  3942. if (fFirstSend)
  3943. {
  3944. //
  3945. // Don't start the timer yet, but start the sender thread
  3946. //
  3947. PgmAttachToProcessForVMAccess (pSend, &ApcState, &fAttached, REF_PROCESS_ATTACH_START_SENDER_THREAD);
  3948. status = PsCreateSystemThread (&pSend->pSender->SendHandle,
  3949. PROCESS_ALL_ACCESS,
  3950. NULL,
  3951. NULL,
  3952. NULL,
  3953. SenderWorkerThread,
  3954. pSend);
  3955. if (!NT_SUCCESS (status))
  3956. {
  3957. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_START_SENDER_THREAD);
  3958. if (fResourceAcquired)
  3959. {
  3960. PgmReleaseResource (&pSend->pSender->Resource);
  3961. }
  3962. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext1);
  3963. if (pSendContext2)
  3964. {
  3965. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext2);
  3966. }
  3967. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  3968. PgmLog (PGM_LOG_ERROR, DBG_SEND, "PgmSend",
  3969. "status=<%x> starting sender thread\n", status);
  3970. return (status);
  3971. }
  3972. //
  3973. // Close the handle to the thread so that it goes away when the
  3974. // thread terminates
  3975. //
  3976. ZwClose (pSend->pSender->SendHandle);
  3977. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_START_SENDER_THREAD);
  3978. PgmLock (&PgmDynamicConfig, OldIrq1);
  3979. IoAcquireCancelSpinLock (&OldIrq2);
  3980. PgmLock (pAddress, OldIrq3);
  3981. PgmLock (pSend, OldIrq4);
  3982. pSend->SessionFlags &= ~PGM_SESSION_FLAG_FIRST_PACKET;
  3983. pSend->pSender->pAddress = pAddress;
  3984. pSend->pSender->LastODataSentSequenceNumber = -1;
  3985. //
  3986. // Set the SYN flag for the first packet
  3987. //
  3988. pSendContext1->DataOptions |= PGM_OPTION_FLAG_SYN; // First packet only
  3989. pSendContext1->DataOptionsLength += PGM_PACKET_OPT_SYN_LENGTH;
  3990. PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_TIMER_RUNNING, TRUE);
  3991. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SEND_IN_PROGRESS, TRUE);
  3992. //
  3993. // Now, set and start the timer
  3994. //
  3995. pSend->pSender->LastTimeout = KeQueryPerformanceCounter (&Frequency);
  3996. pSend->pSender->TimeoutGranularity.QuadPart = (Frequency.QuadPart * BASIC_TIMER_GRANULARITY_IN_MSECS) / 1000;
  3997. pSend->pSender->TimerTickCount = 1;
  3998. PgmInitTimer (&pSend->SessionTimer);
  3999. PgmStartTimer (&pSend->SessionTimer, BASIC_TIMER_GRANULARITY_IN_MSECS, SendSessionTimeout, pSend);
  4000. }
  4001. else
  4002. {
  4003. PgmLock (&PgmDynamicConfig, OldIrq1);
  4004. IoAcquireCancelSpinLock (&OldIrq2);
  4005. PgmLock (pAddress, OldIrq3);
  4006. PgmLock (pSend, OldIrq4);
  4007. }
  4008. pSendContext1->pSend = pSend;
  4009. pSendContext1->pIrp = pIrp;
  4010. pSendContext1->pIrpToComplete = pIrp;
  4011. pSendContext1->NextDataOffsetInMdl = 0;
  4012. pSendContext1->SendNumber = pSend->pSender->NextSendNumber++;
  4013. pSendContext1->DataPayloadSize = pSend->pSender->MaxPayloadSize;
  4014. pSendContext1->DataOptions |= pSend->pSender->DataOptions; // Attach options common for every send
  4015. pSendContext1->DataOptionsLength += pSend->pSender->DataOptionsLength;
  4016. pSendContext1->pLastMessageVariableTGPacket = (PVOID) -1; // FEC-specific
  4017. if (pSend->pSender->ThisSendMessageLength)
  4018. {
  4019. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmSend",
  4020. "Send # [%d]: MessageLength=<%d>, BytesSent=<%d>, BytesInSend=<%d>\n",
  4021. pSendContext1->SendNumber, pSend->pSender->ThisSendMessageLength,
  4022. pSend->pSender->BytesSent, pTdiRequest->SendLength);
  4023. pSendContext1->ThisMessageLength = pSend->pSender->ThisSendMessageLength;
  4024. pSendContext1->LastMessageOffset = pSend->pSender->BytesSent;
  4025. if (pSendContext2)
  4026. {
  4027. //
  4028. // First, set the parameters for SendDataContext1
  4029. //
  4030. pSendContext1->BytesInSend = BytesLeftInMessage;
  4031. pSendContext1->pIrpToComplete = NULL; // This Irp will be completed by the Context2
  4032. //
  4033. // Now, set the parameters for SendDataContext1
  4034. //
  4035. pSendContext2->pSend = pSend;
  4036. pSendContext2->pIrp = pIrp;
  4037. pSendContext2->pIrpToComplete = pIrp;
  4038. pSendContext2->SendNumber = pSend->pSender->NextSendNumber++;
  4039. pSendContext2->DataPayloadSize = pSend->pSender->MaxPayloadSize;
  4040. pSendContext2->DataOptions |= pSend->pSender->DataOptions; // Attach options common for every send
  4041. pSendContext2->DataOptionsLength += pSend->pSender->DataOptionsLength;
  4042. pSendContext2->pLastMessageVariableTGPacket = (PVOID) -1; // FEC-specific
  4043. pSendContext2->ThisMessageLength = pTdiRequest->SendLength - BytesLeftInMessage;
  4044. pSendContext2->BytesInSend = pSendContext2->ThisMessageLength;
  4045. pSendContext2->NextDataOffsetInMdl = BytesLeftInMessage;
  4046. }
  4047. else
  4048. {
  4049. pSendContext1->BytesInSend = pTdiRequest->SendLength;
  4050. }
  4051. pSend->pSender->BytesSent += pSendContext1->BytesInSend;
  4052. if (pSend->pSender->BytesSent == pSend->pSender->ThisSendMessageLength)
  4053. {
  4054. pSend->pSender->BytesSent = pSend->pSender->ThisSendMessageLength = 0;
  4055. }
  4056. }
  4057. else
  4058. {
  4059. pSendContext1->ThisMessageLength = pTdiRequest->SendLength;
  4060. pSendContext1->BytesInSend = pTdiRequest->SendLength;
  4061. }
  4062. // If the total Message length exceeds that of PayloadSize/Packet, then we need to fragment
  4063. if ((pSendContext1->ThisMessageLength > pSendContext1->DataPayloadSize) ||
  4064. (pSendContext1->ThisMessageLength > pSendContext1->BytesInSend))
  4065. {
  4066. pSendContext1->DataOptions |= PGM_OPTION_FLAG_FRAGMENT;
  4067. pSendContext1->DataOptionsLength += PGM_PACKET_OPT_FRAGMENT_LENGTH;
  4068. pSendContext1->NumPacketsRemaining = (pSendContext1->BytesInSend +
  4069. (pSend->pSender->MaxPayloadSize - 1)) /
  4070. pSend->pSender->MaxPayloadSize;
  4071. ASSERT (pSendContext1->NumPacketsRemaining >= 1);
  4072. }
  4073. else
  4074. {
  4075. pSendContext1->NumPacketsRemaining = 1;
  4076. }
  4077. pSend->pSender->NumPacketsRemaining += pSendContext1->NumPacketsRemaining;
  4078. // Adjust the OptionsLength for the Packet Extension and determine
  4079. if (pSendContext1->DataOptions)
  4080. {
  4081. pSendContext1->DataOptionsLength += PGM_PACKET_EXTENSION_LENGTH;
  4082. }
  4083. pSendContext1->BytesLeftToPacketize = pSendContext1->BytesInSend;
  4084. InsertTailList (&pSend->pSender->PendingSends, &pSendContext1->Linkage);
  4085. pSend->pSender->NumODataRequestsPending++;
  4086. //
  4087. // Do the same for Context2, if applicable
  4088. if (pSendContext2)
  4089. {
  4090. //
  4091. // Interlink the 2 Send requests
  4092. //
  4093. pSendContext2->pMessage2Request = pSendContext1;
  4094. pSendContext1->pMessage2Request = pSendContext2;
  4095. PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW, TRUE);
  4096. if (pSendContext2->ThisMessageLength > pSendContext1->DataPayloadSize)
  4097. {
  4098. pSendContext2->DataOptions |= PGM_OPTION_FLAG_FRAGMENT;
  4099. pSendContext2->DataOptionsLength += PGM_PACKET_OPT_FRAGMENT_LENGTH;
  4100. pSendContext2->NumPacketsRemaining = (pSendContext2->BytesInSend +
  4101. (pSend->pSender->MaxPayloadSize - 1)) /
  4102. pSend->pSender->MaxPayloadSize;
  4103. ASSERT (pSendContext2->NumPacketsRemaining >= 1);
  4104. }
  4105. else
  4106. {
  4107. pSendContext2->NumPacketsRemaining = 1;
  4108. }
  4109. pSend->pSender->NumPacketsRemaining += pSendContext2->NumPacketsRemaining;
  4110. // Adjust the OptionsLength for the Packet Extension and determine
  4111. if (pSendContext2->DataOptions)
  4112. {
  4113. pSendContext2->DataOptionsLength += PGM_PACKET_EXTENSION_LENGTH;
  4114. }
  4115. pSendContext2->BytesLeftToPacketize = pSendContext2->BytesInSend;
  4116. InsertTailList (&pSend->pSender->PendingSends, &pSendContext2->Linkage);
  4117. pSend->pSender->NumODataRequestsPending++;
  4118. }
  4119. if (!NT_SUCCESS (PgmCheckSetCancelRoutine (pIrp, PgmCancelSendIrp, TRUE)))
  4120. {
  4121. pSend->SessionFlags |= PGM_SESSION_SENDS_CANCELLED;
  4122. pSend->pSender->NumODataRequestsPending--;
  4123. pSend->pSender->NumPacketsRemaining -= pSendContext1->NumPacketsRemaining;
  4124. RemoveEntryList (&pSendContext1->Linkage);
  4125. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext1);
  4126. if (pSendContext2)
  4127. {
  4128. pSend->pSender->NumODataRequestsPending--;
  4129. pSend->pSender->NumPacketsRemaining -= pSendContext2->NumPacketsRemaining;
  4130. RemoveEntryList (&pSendContext2->Linkage);
  4131. ExFreeToNPagedLookasideList (&pSend->pSender->SendContextLookaside, pSendContext2);
  4132. }
  4133. PgmUnlock (pSend, OldIrq4);
  4134. PgmUnlock (pAddress, OldIrq3);
  4135. IoReleaseCancelSpinLock (OldIrq2);
  4136. PgmUnlock (&PgmDynamicConfig, OldIrq1);
  4137. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  4138. if (pSendContext2)
  4139. {
  4140. PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_SEND_IN_WINDOW);
  4141. }
  4142. PgmLog (PGM_LOG_ERROR, (DBG_RECEIVE | DBG_ADDRESS | DBG_CONNECT), "PgmReceive",
  4143. "Could not set Cancel routine on Send Irp=<%p>, pSend=<%p>, pAddress=<%p>\n",
  4144. pIrp, pSend, pAddress);
  4145. return (STATUS_CANCELLED);
  4146. }
  4147. IoReleaseCancelSpinLock (OldIrq4);
  4148. PgmUnlock (pAddress, OldIrq3);
  4149. PgmUnlock (&PgmDynamicConfig, OldIrq2);
  4150. if (fResourceAcquired)
  4151. {
  4152. // PgmPrepareNextSend (pSend, &OldIrq1, TRUE, TRUE);
  4153. }
  4154. if (pSend->pSender->CurrentBytesSendable >= pAddress->OutIfMTU)
  4155. {
  4156. //
  4157. // Send a synchronization event to the sender thread to
  4158. // send the next available data
  4159. //
  4160. KeSetEvent (&pSend->pSender->SendEvent, 0, FALSE);
  4161. }
  4162. PgmUnlock (pSend, OldIrq1);
  4163. if (fResourceAcquired)
  4164. {
  4165. PgmReleaseResource (&pSend->pSender->Resource);
  4166. }
  4167. PgmLog (PGM_LOG_INFORM_PATH, DBG_SEND, "PgmSend",
  4168. "[%d] Send pending for pIrp=<%p>, pSendContext=<%p -- %p>\n",
  4169. pSendContext1->SendNumber, pIrp, pSendContext1, pSendContext2);
  4170. return (STATUS_PENDING);
  4171. }