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.

3676 lines
110 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. sendeng.c
  5. Abstract:
  6. This module contains code that implements the send engine for the
  7. Jetbeui transport provider. This code is responsible for the following
  8. basic activities, including some subordinate glue.
  9. 1. Packetizing TdiSend requests already queued up on a TP_CONNECTION
  10. object, using I-frame packets acquired from the PACKET.C module,
  11. and turning them into shippable packets and placing them on the
  12. TP_LINK's WackQ. In the process of doing this, the packets are
  13. actually submitted as I/O requests to the Physical Provider, in
  14. the form of PdiSend requests.
  15. 2. Retiring packets queued to a TP_LINK's WackQ and returning them to
  16. the device context's pool for use by other links. In the process
  17. of retiring acked packets, step 1 may be reactivated.
  18. 3. Resending packets queued to a TP_LINK's WackQ because of a reject
  19. condition on the link. This involves no state update in the
  20. TP_CONNECTION object.
  21. 4. Handling of Send completion events from the Physical Provider,
  22. to allow proper synchronization of the reuse of packets.
  23. 5. Completion of TdiSend requests. This is triggered by the receipt
  24. (in IFRAMES.C) of a DataAck frame, or by a combination of other
  25. frames when the proper protocol has been negotiated. One routine
  26. in this routine is responsible for the actual mechanics of TdiSend
  27. request completion.
  28. Author:
  29. David Beaver (dbeaver) 1-July-1991
  30. Environment:
  31. Kernel mode
  32. Revision History:
  33. --*/
  34. #include "precomp.h"
  35. #pragma hdrstop
  36. #if DBG
  37. extern ULONG NbfSendsIssued;
  38. extern ULONG NbfSendsCompletedInline;
  39. extern ULONG NbfSendsCompletedOk;
  40. extern ULONG NbfSendsCompletedFail;
  41. extern ULONG NbfSendsPended;
  42. extern ULONG NbfSendsCompletedAfterPendOk;
  43. extern ULONG NbfSendsCompletedAfterPendFail;
  44. #endif
  45. //
  46. // Temporary variables to control piggyback ack usage.
  47. //
  48. #define NbfUsePiggybackAcks 1
  49. #if DBG
  50. ULONG NbfDebugPiggybackAcks = 0;
  51. #endif
  52. #if DBG
  53. //
  54. // *** This is the original version of StartPacketizingConnection, which
  55. // is now a macro on the free build. It has been left here as the
  56. // fully-commented version of the code.
  57. //
  58. VOID
  59. StartPacketizingConnection(
  60. PTP_CONNECTION Connection,
  61. IN BOOLEAN Immediate
  62. )
  63. /*++
  64. Routine Description:
  65. This routine is called to place a connection on the PacketizeQueue
  66. of its device context object. Then this routine starts packetizing
  67. the first connection on that queue.
  68. *** The Connection LinkSpinLock must be held on entry to this routine.
  69. *** THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
  70. Arguments:
  71. Connection - Pointer to a TP_CONNECTION object.
  72. Immediate - TRUE if the connection should be packetized
  73. immediately; FALSE if the connection should be queued
  74. up for later packetizing (implies that ReceiveComplete
  75. will be called in the future, which packetizes always).
  76. NOTE: If this is TRUE, it also implies that we have
  77. a connection reference of type CREF_BY_ID which we
  78. will "convert" into the CREF_PACKETIZE_QUEUE one.
  79. Return Value:
  80. none.
  81. --*/
  82. {
  83. PDEVICE_CONTEXT DeviceContext;
  84. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  85. NbfPrint1 ("StartPacketizingConnection: Entered for connection %lx.\n",
  86. Connection);
  87. }
  88. DeviceContext = Connection->Provider;
  89. //
  90. // If this connection's SendState is set to PACKETIZE and if
  91. // we are not already on the PacketizeQueue, then go ahead and
  92. // append us to the end of that queue, and remember that we're
  93. // on it by setting the CONNECTION_FLAGS_PACKETIZE bitflag.
  94. //
  95. // Also don't queue it if the connection is stopping.
  96. //
  97. if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
  98. !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE) &&
  99. (Connection->Flags & CONNECTION_FLAGS_READY)) {
  100. ASSERT (!(Connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
  101. Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
  102. if (!Immediate) {
  103. NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
  104. } else {
  105. #if DBG
  106. NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
  107. NbfDereferenceConnection("temp TdiSend", Connection, CREF_BY_ID);
  108. #endif
  109. }
  110. ExInterlockedInsertTailList(
  111. &DeviceContext->PacketizeQueue,
  112. &Connection->PacketizeLinkage,
  113. &DeviceContext->SpinLock);
  114. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  115. } else {
  116. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  117. if (Immediate) {
  118. NbfDereferenceConnection("temp TdiSend", Connection, CREF_BY_ID);
  119. }
  120. }
  121. if (Immediate) {
  122. PacketizeConnections (DeviceContext);
  123. }
  124. } /* StartPacketizingConnection */
  125. #endif
  126. VOID
  127. PacketizeConnections(
  128. PDEVICE_CONTEXT DeviceContext
  129. )
  130. /*++
  131. Routine Description:
  132. This routine attempts to packetize all connections waiting on the
  133. PacketizeQueue of the DeviceContext.
  134. Arguments:
  135. DeviceContext - Pointer to a DEVICE_CONTEXT object.
  136. Return Value:
  137. none.
  138. --*/
  139. {
  140. PLIST_ENTRY p;
  141. PTP_CONNECTION Connection;
  142. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  143. NbfPrint1 ("PacketizeConnections: Entered for device context %lx.\n",
  144. DeviceContext);
  145. }
  146. //
  147. // Pick connections off of the device context's packetization queue
  148. // until there are no more left to pick off. For each one, we call
  149. // PacketizeSend. Note this routine can be executed concurrently
  150. // on multiple processors and it doesn't matter; multiple connections
  151. // may be packetized concurrently.
  152. //
  153. while (TRUE) {
  154. p = ExInterlockedRemoveHeadList(
  155. &DeviceContext->PacketizeQueue,
  156. &DeviceContext->SpinLock);
  157. if (p == NULL) {
  158. break;
  159. }
  160. Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
  161. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  162. if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
  163. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  164. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  165. NbfDereferenceConnection ("No longer packetizing", Connection, CREF_PACKETIZE_QUEUE);
  166. } else {
  167. NbfReferenceSendIrp ("Packetize", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
  168. PacketizeSend (Connection, FALSE); // releases the lock.
  169. }
  170. }
  171. } /* PacketizeConnections */
  172. VOID
  173. PacketizeSend(
  174. IN PTP_CONNECTION Connection,
  175. IN BOOLEAN Direct
  176. )
  177. /*++
  178. Routine Description:
  179. This routine packetizes the current TdiSend request on the specified
  180. connection as much as limits will permit. A given here is that there
  181. is an active send on the connection that needs further packetization.
  182. NOTE: This routine is called with the connection spinlock held and
  183. returns with it released. THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
  184. Arguments:
  185. Connection - Pointer to a TP_CONNECTION object.
  186. Direct - TRUE if we are called from TdiSend. This implies that
  187. the connection does not have a reference of type CREF_SEND_IRP,
  188. which we need to add before we leave.
  189. Return Value:
  190. none.
  191. --*/
  192. {
  193. ULONG MaxFrameSize, FrameSize;
  194. ULONG PacketBytes;
  195. PNDIS_BUFFER PacketDescriptor;
  196. PDEVICE_CONTEXT DeviceContext;
  197. PTP_PACKET Packet;
  198. NTSTATUS Status;
  199. PNBF_HDR_CONNECTION NbfHeader;
  200. BOOLEAN LinkCheckpoint;
  201. BOOLEAN SentPacket = FALSE;
  202. BOOLEAN ExitAfterSendOnePacket = FALSE;
  203. PIO_STACK_LOCATION IrpSp;
  204. ULONG LastPacketLength;
  205. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  206. NbfPrint1 ("PacketizeSend: Entered for connection %lx.\n", Connection);
  207. }
  208. DeviceContext = Connection->Provider;
  209. ASSERT (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
  210. //
  211. // Just loop until one of three events happens: (1) we run out of
  212. // packets from NbfCreatePacket, (2) we completely packetize the send,
  213. // or (3) we can't send any more packets because SendOnePacket failed.
  214. //
  215. #if DBG
  216. //
  217. // Convert the queue reference into a packetize one. It is OK
  218. // to do this with the lock held because we know that the refcount
  219. // must already be at least one, so we don't drop to zero.
  220. //
  221. NbfReferenceConnection ("PacketizeSend", Connection, CREF_PACKETIZE);
  222. NbfDereferenceConnection ("Off packetize queue", Connection, CREF_PACKETIZE_QUEUE);
  223. #endif
  224. MaxFrameSize = Connection->MaximumDataSize;
  225. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  226. NbfPrint1 ("PacketizeSend: MaxFrameSize for user data=%ld.\n", MaxFrameSize);
  227. }
  228. //
  229. // It is possible for a frame to arrive during the middle of this loop
  230. // (such as a NO_RECEIVE) that will put us into a new state (such as
  231. // W_RCVCONT). For this reason, we have to check the state every time
  232. // (at the end of the loop).
  233. //
  234. do {
  235. if (!NT_SUCCESS (NbfCreatePacket (DeviceContext, Connection->Link, &Packet))) {
  236. //
  237. // We need a packet to finish packetizing the current send, but
  238. // there are no more packets available in the pool right now.
  239. // Set our send state to W_PACKET, and put this connection on
  240. // the PacketWaitQueue of the device context object. Then,
  241. // when NbfDestroyPacket frees up a packet, it will check this
  242. // queue for starved connections, and if it finds one, it will
  243. // take a connection off the list and set its send state to
  244. // SENDSTATE_PACKETIZE and put it on the PacketizeQueue.
  245. //
  246. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  247. NbfPrint0 ("PacketizeSend: NbfCreatePacket failed.\n");
  248. }
  249. Connection->SendState = CONNECTION_SENDSTATE_W_PACKET;
  250. //
  251. // Clear the PACKETIZE flag, indicating that we're no longer
  252. // on the PacketizeQueue or actively packetizing. The flag
  253. // was set by StartPacketizingConnection to indicate that
  254. // the connection was already on the PacketizeQueue.
  255. //
  256. // Don't queue him if the connection is stopping.
  257. //
  258. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  259. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  260. #if DBG
  261. if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
  262. DbgPrint ("NBF: Trying to PacketWait stopping connection %lx\n", Connection);
  263. DbgBreakPoint();
  264. }
  265. #endif
  266. Connection->Flags |= CONNECTION_FLAGS_W_PACKETIZE;
  267. if (!Connection->OnPacketWaitQueue) {
  268. Connection->OnPacketWaitQueue = TRUE;
  269. InsertTailList(
  270. &DeviceContext->PacketWaitQueue,
  271. &Connection->PacketWaitLinkage);
  272. }
  273. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  274. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  275. if (!SentPacket) {
  276. NbfDereferenceSendIrp ("No packet", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
  277. }
  278. if (Direct) {
  279. NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
  280. }
  281. NbfDereferenceConnection ("No packet", Connection, CREF_PACKETIZE);
  282. return;
  283. }
  284. //
  285. // Set the length of the packet now, while only the
  286. // header is attached.
  287. //
  288. NbfSetNdisPacketLength(
  289. Packet->NdisPacket,
  290. Connection->Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
  291. // Add a reference count to the request, and keep track of
  292. // which request it is. We rely on NbfDestroyPacket to
  293. // remove the reference.
  294. IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp);
  295. Packet->Owner = IrpSp;
  296. // Packet->Action = PACKET_ACTION_IRP_SP;
  297. IF_NBFDBG (NBF_DEBUG_REQUEST) {
  298. NbfPrint2 ("PacketizeSend: Packet %x ref IrpSp %x.\n", Packet, Packet->Owner);
  299. }
  300. //
  301. // For performance reasons, the first time through here on
  302. // a direct call, we have a IrpSp reference already.
  303. //
  304. if (SentPacket) {
  305. NbfReferenceSendIrp ("Packetize", IrpSp, RREF_PACKET);
  306. }
  307. //
  308. // Now build a DATA_ONLY_LAST header in this frame. If it
  309. // turns out we need a DFM, we change it. The header we copy
  310. // already has ResponseCorrelator set to our current correlator
  311. // and TransmitCorrelator set to the last one we received from
  312. // him (if we do not piggyback an ack, then we zero out
  313. // TransmitCorrelator).
  314. //
  315. NbfHeader = (PNBF_HDR_CONNECTION)&(Packet->Header[Connection->Link->HeaderLength + sizeof(DLC_I_FRAME)]);
  316. *(NBF_HDR_CONNECTION UNALIGNED *)NbfHeader = Connection->NetbiosHeader;
  317. ASSERT (RESPONSE_CORR(NbfHeader) != 0);
  318. //
  319. // Determine if we need the resynch bit here.
  320. //
  321. if (Connection->Flags & CONNECTION_FLAGS_RESYNCHING) {
  322. NbfHeader->Data2Low = 1;
  323. Connection->Flags &= ~CONNECTION_FLAGS_RESYNCHING;
  324. } else {
  325. NbfHeader->Data2Low = 0;
  326. }
  327. //
  328. // build an NDIS_BUFFER chain that describes the buffer we're using, and
  329. // thread it off the NdisBuffer. This chain may not complete the
  330. // packet, as the remaining part of the MDL chain may be shorter than
  331. // the packet.
  332. //
  333. FrameSize = MaxFrameSize;
  334. //
  335. // Check if we have less than FrameSize left to send.
  336. //
  337. if (Connection->sp.MessageBytesSent + FrameSize > Connection->CurrentSendLength) {
  338. FrameSize = Connection->CurrentSendLength - Connection->sp.MessageBytesSent;
  339. }
  340. //
  341. // Make a copy of the MDL chain for this send, unless
  342. // there are zero bytes left.
  343. //
  344. if (FrameSize != 0) {
  345. //
  346. // If the whole send will fit inside one packet,
  347. // then there is no need to duplicate the MDL
  348. // (note that this may include multi-MDL sends).
  349. //
  350. if ((Connection->sp.SendByteOffset == 0) &&
  351. (Connection->CurrentSendLength == FrameSize)) {
  352. PacketDescriptor = (PNDIS_BUFFER)Connection->sp.CurrentSendMdl;
  353. PacketBytes = FrameSize;
  354. Connection->sp.CurrentSendMdl = NULL;
  355. Connection->sp.SendByteOffset = FrameSize;
  356. Packet->PacketNoNdisBuffer = TRUE;
  357. } else {
  358. Status = BuildBufferChainFromMdlChain (
  359. DeviceContext,
  360. Connection->sp.CurrentSendMdl,
  361. Connection->sp.SendByteOffset,
  362. FrameSize,
  363. &PacketDescriptor,
  364. &Connection->sp.CurrentSendMdl,
  365. &Connection->sp.SendByteOffset,
  366. &PacketBytes);
  367. if (!NT_SUCCESS(Status)) {
  368. if (NbfHeader->Data2Low) {
  369. Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
  370. }
  371. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  372. NbfDereferencePacket (Packet); // remove creation hold.
  373. goto BufferChainFailure;
  374. }
  375. }
  376. //
  377. // Chain the buffers to the packet, unless there
  378. // are zero bytes of data.
  379. //
  380. Connection->sp.MessageBytesSent += PacketBytes;
  381. NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor);
  382. } else {
  383. PacketBytes = 0;
  384. Connection->sp.CurrentSendMdl = NULL;
  385. }
  386. {
  387. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  388. {PNDIS_BUFFER NdisBuffer;
  389. NdisQueryPacket(Packet->NdisPacket, NULL, NULL, &NdisBuffer, NULL);
  390. NbfPrint1 ("PacketizeSend: NDIS_BUFFER Built, chain is: %lx is Packet->Head\n", NdisBuffer);
  391. NdisGetNextBuffer (NdisBuffer, &NdisBuffer);
  392. while (NdisBuffer != NULL) {
  393. NbfPrint1 (" %lx is Next\n",
  394. NdisBuffer);
  395. NdisGetNextBuffer (NdisBuffer, &NdisBuffer);
  396. }}
  397. }
  398. //
  399. // Have we run out of Mdl Chain in this request?
  400. //
  401. #if DBG
  402. if (PacketBytes < FrameSize) {
  403. ASSERT (Connection->sp.CurrentSendMdl == NULL);
  404. }
  405. #endif
  406. if ((Connection->sp.CurrentSendMdl == NULL) ||
  407. (Connection->CurrentSendLength <= Connection->sp.MessageBytesSent)) {
  408. //
  409. // Yep. We know that we've exhausted the current request's buffer
  410. // here, so see if there's another request without EOF set that we
  411. // can build start throwing into this packet.
  412. //
  413. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  414. NbfPrint0 ("PacketizeSend: Used up entire request.\n");
  415. }
  416. if (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) {
  417. //
  418. // We are sending the last packet in a message. Change
  419. // the packet type and indicate in the connection object's
  420. // send state that we are waiting for a DATA_ACK NetBIOS-
  421. // level acknowlegement.
  422. //
  423. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  424. NbfPrint0 ("PacketizeSend: Request has EOR, making pkt a DOL.\n");
  425. }
  426. //
  427. // Keep track of how many consecutive sends we have done.
  428. //
  429. Connection->ConsecutiveSends++;
  430. Connection->ConsecutiveReceives = 0;
  431. //
  432. // Change it to a DOL with piggyback ack allowed if wanted.
  433. //
  434. ASSERT (NbfHeader->Command == NBF_CMD_DATA_ONLY_LAST);
  435. if (!(IRP_SEND_FLAGS(IrpSp) &
  436. TDI_SEND_NO_RESPONSE_EXPECTED) &&
  437. (Connection->ConsecutiveSends < 2)) {
  438. if (NbfUsePiggybackAcks) {
  439. NbfHeader->Data1 |= DOL_OPTIONS_ACK_W_DATA_ALLOWED;
  440. }
  441. }
  442. Connection->SendState = CONNECTION_SENDSTATE_W_ACK;
  443. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  444. ExitAfterSendOnePacket = TRUE;
  445. } else {
  446. //
  447. // We are sending the last packet in this request. If there
  448. // are more requests in the connection's SendQueue, then
  449. // advance complex send pointer to point to the next one
  450. // in line. Otherwise, if there aren't any more requests
  451. // ready to packetize, then we enter the W_EOR state and
  452. // stop packetizing. Note that we're waiting here for the TDI
  453. // client to come up with data to send; we're just hanging out
  454. // until then.
  455. //
  456. // DGB: Note that this will allow the last packet in the
  457. // request to be smaller than the max packet length. This
  458. // is not addressed anywhere that I can find in the NBF
  459. // spec, and will be interesting to test against a non-NT
  460. // NBF protocol.
  461. //
  462. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  463. NbfPrint0 ("PacketizeSend: Request doesn't have EOR.\n");
  464. }
  465. NbfHeader->Command = NBF_CMD_DATA_FIRST_MIDDLE;
  466. if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) {
  467. Connection->SendState = CONNECTION_SENDSTATE_W_EOR;
  468. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  469. ExitAfterSendOnePacket = TRUE;
  470. } else {
  471. Connection->sp.CurrentSendIrp =
  472. CONTAINING_RECORD (
  473. Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink,
  474. IRP,
  475. Tail.Overlay.ListEntry);
  476. Connection->sp.CurrentSendMdl =
  477. Connection->sp.CurrentSendIrp->MdlAddress;
  478. Connection->sp.SendByteOffset = 0;
  479. Connection->CurrentSendLength +=
  480. IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
  481. }
  482. }
  483. } else {
  484. NbfHeader->Command = NBF_CMD_DATA_FIRST_MIDDLE;
  485. }
  486. //
  487. // Before we release the spinlock, see if we want to
  488. // piggyback an ack on here.
  489. //
  490. if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
  491. //
  492. // Turn off the flags. We don't take it off the queue,
  493. // that will be handled by the timer function.
  494. //
  495. Connection->DeferredFlags &=
  496. ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
  497. ASSERT (DOL_OPTIONS_ACK_INCLUDED == DFM_OPTIONS_ACK_INCLUDED);
  498. #if DBG
  499. if (NbfDebugPiggybackAcks) {
  500. NbfPrint0("A");
  501. }
  502. #endif
  503. //
  504. // TRANSMIT_CORR(NbfHeader) is already set correctly.
  505. //
  506. NbfHeader->Data1 |= DOL_OPTIONS_ACK_INCLUDED;
  507. } else {
  508. TRANSMIT_CORR(NbfHeader) = (USHORT)0;
  509. }
  510. //
  511. // To prevent a send "crossing" the receive and
  512. // causing a bogus piggyback ack timeout (this
  513. // only matters if a receive indication is in
  514. // progress).
  515. //
  516. Connection->CurrentReceiveAckQueueable = FALSE;
  517. SentPacket = TRUE;
  518. LastPacketLength =
  519. sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION) + PacketBytes;
  520. MacModifyHeader(
  521. &DeviceContext->MacInfo,
  522. Packet->Header,
  523. LastPacketLength);
  524. Packet->NdisIFrameLength = LastPacketLength;
  525. ASSERT (Connection->LinkSpinLock == &Connection->Link->SpinLock);
  526. Status = SendOnePacket (Connection, Packet, FALSE, &LinkCheckpoint);
  527. if (Status == STATUS_LINK_FAILED) {
  528. //
  529. // If SendOnePacket failed due to the link being
  530. // dead, then we tear down the link.
  531. //
  532. FailSend (Connection, STATUS_LINK_FAILED, TRUE); // fail the send
  533. NbfDereferencePacket (Packet); // remove creation hold.
  534. if (Direct) {
  535. NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
  536. }
  537. NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
  538. return;
  539. } else {
  540. //
  541. // SendOnePacket returned success, so update our counters;
  542. //
  543. DeviceContext->TempIFrameBytesSent += PacketBytes;
  544. ++DeviceContext->TempIFramesSent;
  545. if ((Status == STATUS_SUCCESS) && LinkCheckpoint) {
  546. //
  547. // We are checkpointing; this means that SendOnePacket
  548. // will already have set the state to W_LINK and turned
  549. // off the PACKETIZE flag, so we should leave. When
  550. // the checkpoint response is received, we will
  551. // resume packetizing. We don't have to worry about
  552. // doing all the other recovery stuff (resetting
  553. // the piggyback ack flag, complex send pointer, etc.)
  554. // because the send did in fact succeed.
  555. //
  556. if (Direct) {
  557. #if DBG
  558. NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
  559. NbfDereferenceConnection ("Link checkpoint", Connection, CREF_PACKETIZE);
  560. #endif
  561. } else {
  562. NbfDereferenceConnection ("Link checkpoint", Connection, CREF_PACKETIZE);
  563. }
  564. return;
  565. } else if (ExitAfterSendOnePacket ||
  566. (Status == STATUS_MORE_PROCESSING_REQUIRED)) {
  567. if (Direct) {
  568. #if DBG
  569. NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
  570. NbfDereferenceConnection ("Packetize done", Connection, CREF_PACKETIZE);
  571. #endif
  572. } else {
  573. NbfDereferenceConnection ("Packetize done", Connection, CREF_PACKETIZE);
  574. }
  575. return;
  576. }
  577. }
  578. }
  579. BufferChainFailure:;
  580. //
  581. // Note that we may have fallen out of the BuildBuffer... if above with
  582. // Status set to STATUS_INSUFFICIENT_RESOURCES. if we have, we'll just
  583. // stick this connection back onto the packetize queue and hope the
  584. // system gets more resources later.
  585. //
  586. if (!NT_SUCCESS (Status)) {
  587. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  588. NbfPrint0 ("PacketizeSend: SendOnePacket failed.\n");
  589. }
  590. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  591. //
  592. // Indicate we're waiting on favorable link conditions.
  593. //
  594. Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
  595. //
  596. // Clear the PACKETIZE flag, indicating that we're no longer
  597. // on the PacketizeQueue or actively packetizing. The flag
  598. // was set by StartPacketizingConnection to indicate that
  599. // the connection was already on the PacketizeQueue.
  600. //
  601. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  602. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  603. //
  604. // If we are exiting and we sent a packet without
  605. // polling, we need to start T1.
  606. //
  607. if (Direct) {
  608. //
  609. // We have to do the CREF_SEND_IRP reference that is missing.
  610. //
  611. #if DBG
  612. NbfReferenceConnection("TdiSend", Connection, CREF_SEND_IRP);
  613. NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
  614. #endif
  615. } else {
  616. NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
  617. }
  618. return;
  619. }
  620. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  621. //
  622. // It is probable that a NetBIOS frame arrived while we released
  623. // the connection's spin lock, so our state has probably changed.
  624. // When we cycle around this loop again, we will have the lock
  625. // again, so we can test the connection's send state.
  626. //
  627. } while (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
  628. //
  629. // Clear the PACKETIZE flag, indicating that we're no longer on the
  630. // PacketizeQueue or actively packetizing. The flag was set by
  631. // StartPacketizingConnection to indicate that the connection was
  632. // already on the PacketizeQueue.
  633. //
  634. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  635. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  636. if (Direct) {
  637. #if DBG
  638. NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
  639. NbfDereferenceConnection ("PacketizeSend done", Connection, CREF_PACKETIZE);
  640. #endif
  641. } else {
  642. NbfDereferenceConnection ("PacketizeSend done", Connection, CREF_PACKETIZE);
  643. }
  644. } /* PacketizeSend */
  645. VOID
  646. CompleteSend(
  647. PTP_CONNECTION Connection,
  648. IN USHORT Correlator
  649. )
  650. /*++
  651. Routine Description:
  652. This routine is called because the connection partner acknowleged
  653. an entire message at the NetBIOS Frames Protocol level, either through
  654. a DATA_ACK response, or a RECEIVE_OUTSTANDING, or RECEIVE_CONTINUE,
  655. or NO_RECEIVE response where the number of bytes specified exactly
  656. matches the number of bytes sent in the message. Here we retire all
  657. of the TdiSends on the connection's SendQueue up to and including the
  658. one with the TDI_END_OF_RECORD bitflag set. For each request, we
  659. complete the I/O.
  660. NOTE: This function is called with the connection spinlock
  661. held and returns with it held, but it may release it in the
  662. middle. THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
  663. Arguments:
  664. Connection - Pointer to a TP_CONNECTION object.
  665. Correlator - The correlator in the DATA_ACK or piggybacked ack.
  666. OldIrqlP - Returns the IRQL at which the connection spinlock
  667. was acquired.
  668. Return Value:
  669. none.
  670. --*/
  671. {
  672. PIRP Irp;
  673. PIO_STACK_LOCATION IrpSp;
  674. PLIST_ENTRY p;
  675. BOOLEAN EndOfRecord;
  676. KIRQL cancelIrql;
  677. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  678. NbfPrint1 ("CompleteSend: Entered for connection %lx.\n", Connection);
  679. }
  680. //
  681. // Make sure that the correlator is the expect one, and
  682. // that we are in a good state (don't worry about locking
  683. // since this is an unusual case anyway).
  684. //
  685. if (Correlator != Connection->NetbiosHeader.ResponseCorrelator) {
  686. NbfPrint0 ("NbfCompleteSend: ack ignored, wrong correlator\n");
  687. return;
  688. }
  689. if (Connection->SendState != CONNECTION_SENDSTATE_W_ACK) {
  690. NbfPrint0 ("NbfCompleteSend: ack not expected\n");
  691. return;
  692. }
  693. //
  694. // Pick off TP_REQUEST objects from the connection's SendQueue until
  695. // we find one with an END_OF_RECORD mark embedded in it.
  696. //
  697. while (!(IsListEmpty(&Connection->SendQueue))) {
  698. //
  699. // We know for a fact that we wouldn't be calling this routine if
  700. // we hadn't received an acknowlegement for an entire message,
  701. // since NBF doesn't provide stream mode sends. Therefore, we
  702. // know that we will run into a request with the END_OF_RECORD
  703. // mark set BEFORE we will run out of requests on that queue,
  704. // so there is no reason to check to see if we ran off the end.
  705. // Note that it's possible that the send has been failed and the
  706. // connection not yet torn down; if this has happened, we could be
  707. // removing from an empty queue here. Make sure that doesn't happen.
  708. //
  709. p = RemoveHeadList(&Connection->SendQueue);
  710. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  711. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  712. EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
  713. #if DBG
  714. NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
  715. NbfCompletedSends[NbfCompletedSendsNext].Request = NULL;
  716. NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_SUCCESS;
  717. NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
  718. #endif
  719. #if DBG
  720. IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
  721. if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_SENDS) != 0){
  722. NbfPrint1 ("CompleteSend: Completing send request %lx\n", Irp);
  723. if (++Connection->DeferredPasses >= 4) {
  724. Connection->DeferredFlags &= ~CONNECTION_FLAGS_DEFERRED_SENDS;
  725. Connection->DeferredPasses = 0;
  726. }
  727. }
  728. }
  729. #endif
  730. //
  731. // Complete the send. Note that this may not actually call
  732. // IoCompleteRequest for the Irp until sometime later, if the
  733. // in-progress LLC resending going on below us needs to complete.
  734. //
  735. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  736. //
  737. // Since the irp is no longer on the send list, the cancel routine
  738. // cannot find it and will just return. We must grab the cancel
  739. // spinlock to lock out the cancel function while we null out
  740. // the Irp->CancelRoutine field.
  741. //
  742. IoAcquireCancelSpinLock(&cancelIrql);
  743. IoSetCancelRoutine(Irp, NULL);
  744. IoReleaseCancelSpinLock(cancelIrql);
  745. NbfCompleteSendIrp (
  746. Irp,
  747. STATUS_SUCCESS,
  748. IRP_SEND_LENGTH(IrpSp));
  749. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  750. ++Connection->TransmittedTsdus;
  751. if (EndOfRecord) {
  752. break;
  753. }
  754. }
  755. //
  756. // We've finished processing the current send. Update our state.
  757. //
  758. // Note: The connection spinlock is held here.
  759. //
  760. Connection->SendState = CONNECTION_SENDSTATE_IDLE;
  761. //
  762. // If there is another send pending on the connection, then initialize
  763. // it and start packetizing it.
  764. //
  765. if (!(IsListEmpty (&Connection->SendQueue))) {
  766. InitializeSend (Connection);
  767. //
  768. // This code is similar to calling StartPacketizingConnection
  769. // with the second parameter FALSE.
  770. //
  771. if ((!(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
  772. (Connection->Flags & CONNECTION_FLAGS_READY)) {
  773. Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
  774. NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
  775. ExInterlockedInsertTailList(
  776. &Connection->Provider->PacketizeQueue,
  777. &Connection->PacketizeLinkage,
  778. &Connection->Provider->SpinLock);
  779. }
  780. }
  781. //
  782. // NOTE: We return with the lock held.
  783. //
  784. } /* CompleteSend */
  785. VOID
  786. FailSend(
  787. IN PTP_CONNECTION Connection,
  788. IN NTSTATUS RequestStatus,
  789. IN BOOLEAN StopConnection
  790. )
  791. /*++
  792. Routine Description:
  793. This routine is called because something on the link caused this send to be
  794. unable to complete. There are a number of possible reasons for this to have
  795. happened, but all will fail with the common error STATUS_LINK_FAILED.
  796. or NO_RECEIVE response where the number of bytes specified exactly
  797. Here we retire all of the TdiSends on the connection's SendQueue up to
  798. and including the current one, which is the one that failed.
  799. Later - Actually, a send failing is cause for the entire circuit to wave
  800. goodbye to this life. We now simply tear down the connection completly.
  801. Any future sends on this connection will be blown away.
  802. NOTE: THIS FUNCTION MUST BE CALLED WITH THE SPINLOCK HELD.
  803. Arguments:
  804. Connection - Pointer to a TP_CONNECTION object.
  805. Return Value:
  806. none.
  807. --*/
  808. {
  809. PIRP Irp;
  810. PIO_STACK_LOCATION IrpSp;
  811. PLIST_ENTRY p;
  812. BOOLEAN EndOfRecord;
  813. BOOLEAN GotCurrent = FALSE;
  814. KIRQL cancelIrql;
  815. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  816. NbfPrint1 ("FailSend: Entered for connection %lx.\n", Connection);
  817. }
  818. //
  819. // Pick off IRP objects from the connection's SendQueue until
  820. // we get to this one. If this one does NOT have an EOF mark set, we'll
  821. // need to keep going until we hit one that does have EOF set. Note that
  822. // this may cause us to continue failing sends that have not yet been
  823. // queued. (We do all this because NBF does not provide stream mode sends.)
  824. //
  825. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  826. NbfReferenceConnection ("Failing Send", Connection, CREF_COMPLETE_SEND);
  827. do {
  828. if (IsListEmpty (&Connection->SendQueue)) {
  829. //
  830. // got an empty list, so we've run out of send requests to fail
  831. // without running into an EOR. Set the connection flag that will
  832. // cause all further sends to be failed up to an EOR and get out
  833. // of here.
  834. //
  835. Connection->Flags |= CONNECTION_FLAGS_FAILING_TO_EOR;
  836. break;
  837. }
  838. p = RemoveHeadList (&Connection->SendQueue);
  839. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  840. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  841. if (Irp == Connection->sp.CurrentSendIrp) {
  842. GotCurrent = TRUE;
  843. }
  844. EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
  845. #if DBG
  846. NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
  847. NbfCompletedSends[NbfCompletedSendsNext].Status = RequestStatus;
  848. NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
  849. #endif
  850. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  851. IoAcquireCancelSpinLock(&cancelIrql);
  852. IoSetCancelRoutine(Irp, NULL);
  853. IoReleaseCancelSpinLock(cancelIrql);
  854. //
  855. // The following dereference will complete the I/O, provided removes
  856. // the last reference on the request object. The I/O will complete
  857. // with the status and information stored in the Irp. Therefore,
  858. // we set those values here before the dereference.
  859. //
  860. NbfCompleteSendIrp (Irp, RequestStatus, 0);
  861. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  862. ++Connection->TransmissionErrors;
  863. } while (!EndOfRecord & !GotCurrent);
  864. //
  865. // We've finished processing the current send. Update our state.
  866. //
  867. Connection->SendState = CONNECTION_SENDSTATE_IDLE;
  868. Connection->sp.CurrentSendIrp = NULL;
  869. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  870. //
  871. // Blow away this connection; a failed send is a terrible thing to waste.
  872. // Note that we are not on any packetizing queues or similar things at this
  873. // point; we'll just disappear into the night.
  874. //
  875. #if MAGIC
  876. if (NbfEnableMagic) {
  877. extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
  878. NbfSendMagicBullet (Connection->Provider, Connection->Link);
  879. }
  880. #endif
  881. if (StopConnection) {
  882. #if DBG
  883. if (NbfDisconnectDebug) {
  884. STRING remoteName, localName;
  885. remoteName.Length = NETBIOS_NAME_LENGTH - 1;
  886. remoteName.Buffer = Connection->RemoteName;
  887. localName.Length = NETBIOS_NAME_LENGTH - 1;
  888. localName.Buffer = Connection->AddressFile->Address->NetworkName->NetbiosName;
  889. NbfPrint2( "FailSend stopping connection to %S from %S\n",
  890. &remoteName, &localName );
  891. }
  892. #endif
  893. NbfStopConnection (Connection, STATUS_LINK_FAILED);
  894. }
  895. #if DBG
  896. //DbgBreakPoint ();
  897. #endif
  898. NbfDereferenceConnection ("FailSend", Connection, CREF_COMPLETE_SEND);
  899. } /* FailSend */
  900. #if DBG
  901. //
  902. // *** This is the original version of InitializeSend, which is now a macro.
  903. // It has been left here as the fully-commented version of the code.
  904. //
  905. VOID
  906. InitializeSend(
  907. PTP_CONNECTION Connection
  908. )
  909. /*++
  910. Routine Description:
  911. This routine is called whenever the next send on a connection should
  912. be initialized; that is, all of the fields associated with the state
  913. of the current send are set to refer to the first send on the SendQueue.
  914. WARNING: This routine is executed with the Connection lock acquired
  915. since it must be atomically executed with the caller's setup.
  916. Arguments:
  917. Connection - Pointer to a TP_CONNECTION object.
  918. Return Value:
  919. none.
  920. --*/
  921. {
  922. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  923. NbfPrint1 ("InitializeSend: Entered for connection %lx.\n", Connection);
  924. }
  925. ASSERT (!IsListEmpty (&Connection->SendQueue));
  926. Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
  927. Connection->FirstSendIrp =
  928. CONTAINING_RECORD (Connection->SendQueue.Flink, IRP, Tail.Overlay.ListEntry);
  929. Connection->FirstSendMdl = Connection->FirstSendIrp->MdlAddress;
  930. Connection->FirstSendByteOffset = 0;
  931. Connection->sp.MessageBytesSent = 0;
  932. Connection->sp.CurrentSendIrp = Connection->FirstSendIrp;
  933. Connection->sp.CurrentSendMdl = Connection->FirstSendMdl;
  934. Connection->sp.SendByteOffset = Connection->FirstSendByteOffset;
  935. Connection->CurrentSendLength =
  936. IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
  937. Connection->StallCount = 0;
  938. Connection->StallBytesSent = 0;
  939. //
  940. // The send correlator isn't used for much; it is used so we
  941. // can distinguish which send a piggyback ack is acking.
  942. //
  943. if (Connection->NetbiosHeader.ResponseCorrelator == 0xffff) {
  944. Connection->NetbiosHeader.ResponseCorrelator = 1;
  945. } else {
  946. ++Connection->NetbiosHeader.ResponseCorrelator;
  947. }
  948. } /* InitializeSend */
  949. #endif
  950. VOID
  951. ReframeSend(
  952. PTP_CONNECTION Connection,
  953. ULONG BytesReceived
  954. )
  955. /*++
  956. Routine Description:
  957. This routine is called to reset the send state variables in the connection
  958. object to correctly point to the first byte of data to be transmitted.
  959. In essence, this is the byte-level acknowlegement processor at the NetBIOS
  960. level for this transport.
  961. This is not straightforward because potentially multiple send requests
  962. may be posted to the connection to comprise a single message. When a
  963. send request has its TDI_END_OF_RECORD option bitflag set, then that
  964. send is the last one to be sent in a logical message. Therefore, we
  965. assume that the multiple-send scenario is the general case.
  966. Arguments:
  967. Connection - Pointer to a TP_CONNECTION object.
  968. BytesReceived - Number of bytes received thus far.
  969. Return Value:
  970. none.
  971. --*/
  972. {
  973. PIRP Irp;
  974. PMDL Mdl;
  975. ULONG Offset;
  976. ULONG BytesLeft;
  977. ULONG MdlBytes;
  978. PLIST_ENTRY p;
  979. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  980. NbfPrint3 ("ReframeSend: Entered for connection %lx, Flags: %lx Current Mdl: %lx\n",
  981. Connection, Connection->Flags, Connection->sp.CurrentSendMdl);
  982. }
  983. //
  984. // The caller is responsible for restarting the packetization process
  985. // on this connection. In some cases (i.e., NO_RECEIVE handler) we
  986. // don't want to start packetizing, so that's why we do it elsewhere.
  987. //
  988. //
  989. // Examine all of the send requests and associated MDL chains starting
  990. // with the first one at the head of the connection's SendQueue, advancing
  991. // our complex current send pointer through the requests and MDL chains
  992. // until we reach the byte count he's specified.
  993. //
  994. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  995. //
  996. // In the case where a local disconnect has been issued, and we get a frame
  997. // that causes us to reframe the send our FirstSendIrp and FirstMdl
  998. // pointers are stale. Catch this condition and prevent faults caused by
  999. // this. A better fix would be to change the logic that switches the
  1000. // connection sendstate from idle to W_LINK to not do that. However, this
  1001. // is a broader change than fixing it right here.
  1002. //
  1003. if (IsListEmpty(&Connection->SendQueue)) {
  1004. RELEASE_DPC_SPIN_LOCK(Connection->LinkSpinLock);
  1005. return;
  1006. }
  1007. BytesLeft = BytesReceived;
  1008. Irp = Connection->FirstSendIrp;
  1009. Mdl = Connection->FirstSendMdl;
  1010. if (Mdl) {
  1011. MdlBytes = MmGetMdlByteCount (Mdl);
  1012. } else {
  1013. MdlBytes = 0; // zero-length send
  1014. }
  1015. Offset = Connection->FirstSendByteOffset;
  1016. #if DBG
  1017. IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
  1018. NbfPrint3 ("ReFrameSend: Called with Connection %lx FirstSend %lx CurrentSend %lx\n",
  1019. Connection, Connection->FirstSendIrp, Connection->sp.CurrentSendIrp);
  1020. Connection->DeferredFlags |= CONNECTION_FLAGS_DEFERRED_SENDS;
  1021. Connection->DeferredPasses = 0;
  1022. }
  1023. #endif
  1024. //
  1025. // We loop through while we have acked bytes left to account for,
  1026. // advancing our pointers and completing any sends that have been
  1027. // completely acked.
  1028. //
  1029. while (BytesLeft != 0) {
  1030. if (Mdl == NULL) {
  1031. KIRQL cancelIrql;
  1032. //
  1033. // We have exhausted the MDL chain on this request, so it has
  1034. // been implicitly acked. That means we must complete the I/O
  1035. // by dereferencing the request before we reframe further.
  1036. //
  1037. p = RemoveHeadList (&Connection->SendQueue);
  1038. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1039. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1040. //
  1041. // Since the irp is no longer on the list, the cancel routine
  1042. // won't find it. Grab the cancel spinlock to synchronize
  1043. // and complete the irp.
  1044. //
  1045. IoAcquireCancelSpinLock(&cancelIrql);
  1046. IoSetCancelRoutine(Irp, NULL);
  1047. IoReleaseCancelSpinLock(cancelIrql);
  1048. NbfCompleteSendIrp (Irp, STATUS_SUCCESS, Offset);
  1049. //
  1050. // Now continue with the next request in the list.
  1051. //
  1052. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1053. p = Connection->SendQueue.Flink;
  1054. if (p == &Connection->SendQueue) {
  1055. ULONG DumpData[2];
  1056. //
  1057. // The byte acknowledgement was for more than the
  1058. // total length of sends we have outstanding; to
  1059. // avoid problems we tear down the connection.
  1060. //
  1061. #if DBG
  1062. NbfPrint2 ("NbfReframeSend: Got %d extra bytes acked on %lx\n",
  1063. BytesLeft, Connection);
  1064. ASSERT (FALSE);
  1065. #endif
  1066. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1067. DumpData[0] = Offset;
  1068. DumpData[1] = BytesLeft;
  1069. NbfWriteGeneralErrorLog(
  1070. Connection->Provider,
  1071. EVENT_TRANSPORT_BAD_PROTOCOL,
  1072. 1,
  1073. STATUS_INVALID_NETWORK_RESPONSE,
  1074. L"REFRAME",
  1075. 2,
  1076. DumpData);
  1077. NbfStopConnection (Connection, STATUS_INVALID_NETWORK_RESPONSE);
  1078. return;
  1079. }
  1080. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1081. Mdl = Irp->MdlAddress;
  1082. MdlBytes = MmGetMdlByteCount (Mdl);
  1083. Offset = 0;
  1084. } else if (MdlBytes > (Offset + BytesLeft)) {
  1085. //
  1086. // This MDL has more data than we really need. Just use
  1087. // part of it. Then get out, because we're done.
  1088. //
  1089. Offset += BytesLeft;
  1090. BytesLeft = 0;
  1091. break;
  1092. } else {
  1093. //
  1094. // This MDL does not have enough data to satisfy the ACK, so
  1095. // use as much data as it has, and cycle around again.
  1096. //
  1097. Offset = 0;
  1098. BytesLeft -= MdlBytes;
  1099. Mdl = Mdl->Next;
  1100. if (Mdl != NULL) {
  1101. MdlBytes = MmGetMdlByteCount (Mdl);
  1102. }
  1103. }
  1104. }
  1105. //
  1106. // Tmp debugging; we want to see if we got byte acked
  1107. // for the entire send. This will break if we have
  1108. // non-EOR sends.
  1109. //
  1110. #if DBG
  1111. if (BytesReceived != 0) {
  1112. ASSERTMSG ("NbfReframeSend: Byte ack for entire send\n",
  1113. Mdl != NULL);
  1114. }
  1115. #endif
  1116. //
  1117. // We've acked some data, possibly on a byte or message boundary.
  1118. // We must pretend we're sending a new message all over again,
  1119. // starting with the byte immediately after the last one he acked.
  1120. //
  1121. Connection->FirstSendIrp = Irp;
  1122. Connection->FirstSendMdl = Mdl;
  1123. Connection->FirstSendByteOffset = Offset;
  1124. //
  1125. // Since we haven't started sending this new reframed message yet,
  1126. // we set our idea of the current complex send pointer to the first
  1127. // complex send pointer.
  1128. //
  1129. Connection->sp.MessageBytesSent = 0;
  1130. Connection->sp.CurrentSendIrp = Irp;
  1131. Connection->sp.CurrentSendMdl = Mdl;
  1132. Connection->sp.SendByteOffset = Offset;
  1133. Connection->CurrentSendLength -= BytesReceived;
  1134. Connection->StallCount = 0;
  1135. Connection->StallBytesSent = 0;
  1136. #if DBG
  1137. IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
  1138. {
  1139. PLIST_ENTRY p;
  1140. NbfPrint0 ("ReFrameSend: Walking Send List:\n");
  1141. for (
  1142. p = Connection->SendQueue.Flink;
  1143. p != &Connection->SendQueue;
  1144. p=p->Flink ) {
  1145. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1146. NbfPrint1 (" Irp %lx\n", Irp);
  1147. }
  1148. }}
  1149. #endif
  1150. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1151. } /* ReframeSend */
  1152. VOID
  1153. NbfCancelSend(
  1154. IN PDEVICE_OBJECT DeviceObject,
  1155. IN PIRP Irp
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine is called by the I/O system to cancel a send.
  1160. The send is found on the connection's send queue; if it is the
  1161. current request it is cancelled and the connection is torn down,
  1162. otherwise it is silently cancelled.
  1163. NOTE: This routine is called with the CancelSpinLock held and
  1164. is responsible for releasing it.
  1165. Arguments:
  1166. DeviceObject - Pointer to the device object for this driver.
  1167. Irp - Pointer to the request packet representing the I/O request.
  1168. Return Value:
  1169. none.
  1170. --*/
  1171. {
  1172. KIRQL oldirql, oldirql1;
  1173. PIO_STACK_LOCATION IrpSp;
  1174. PTP_CONNECTION Connection;
  1175. PIRP SendIrp;
  1176. PLIST_ENTRY p;
  1177. BOOLEAN Found;
  1178. UNREFERENCED_PARAMETER (DeviceObject);
  1179. //
  1180. // Get a pointer to the current stack location in the IRP. This is where
  1181. // the function codes and parameters are stored.
  1182. //
  1183. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  1184. ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1185. (IrpSp->MinorFunction == TDI_SEND));
  1186. Connection = IrpSp->FileObject->FsContext;
  1187. //
  1188. // Since this IRP is still in the cancellable state, we know
  1189. // that the connection is still around (although it may be in
  1190. // the process of being torn down).
  1191. //
  1192. //
  1193. // See if this is the IRP for the current send request.
  1194. //
  1195. ACQUIRE_SPIN_LOCK (Connection->LinkSpinLock, &oldirql);
  1196. NbfReferenceConnection ("Cancelling Send", Connection, CREF_COMPLETE_SEND);
  1197. p = Connection->SendQueue.Flink;
  1198. SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1199. if (SendIrp == Irp) {
  1200. //
  1201. // yes, it is the first one on the send queue, so
  1202. // trash the send/connection. The first send is a special case
  1203. // there are multiple pointers to the send request. Just stop the
  1204. // connection.
  1205. //
  1206. // p = RemoveHeadList (&Connection->SendQueue);
  1207. #if DBG
  1208. NbfCompletedSends[NbfCompletedSendsNext].Irp = SendIrp;
  1209. NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
  1210. NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
  1211. #endif
  1212. //
  1213. // Prevent anyone from getting in to packetize before we
  1214. // call NbfStopConnection.
  1215. //
  1216. Connection->SendState = CONNECTION_SENDSTATE_IDLE;
  1217. RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
  1218. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1219. #if DBG
  1220. DbgPrint("NBF: Canceled in-progress send %lx on %lxn",
  1221. SendIrp, Connection);
  1222. #endif
  1223. KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
  1224. //
  1225. // The following dereference will complete the I/O, provided removes
  1226. // the last reference on the request object. The I/O will complete
  1227. // with the status and information stored in the Irp. Therefore,
  1228. // we set those values here before the dereference.
  1229. //
  1230. // NbfCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
  1231. //
  1232. // Since we are cancelling the current send, blow away
  1233. // the connection.
  1234. //
  1235. NbfStopConnection (Connection, STATUS_CANCELLED);
  1236. KeLowerIrql (oldirql1);
  1237. } else {
  1238. //
  1239. // Scan through the list, looking for this IRP. If we
  1240. // cancel anything up to the first EOR on the list
  1241. // we still tear down the connection since this would
  1242. // mess up our packetizing otherwise. We set CancelledFirstEor
  1243. // to FALSE when we pass an IRP without SEND_PARTIAL.
  1244. //
  1245. // NO MATTER WHAT WE MUST SHUT DOWN THE CONNECTION!!!!
  1246. #if 0
  1247. if (!(IRP_SEND_FLAGS(IoGetCurrentIrpStackLocation(SendIrp)) & TDI_SEND_PARTIAL)) {
  1248. CancelledFirstEor = FALSE;
  1249. } else {
  1250. CancelledFirstEor = TRUE;
  1251. }
  1252. #endif
  1253. Found = FALSE;
  1254. p = p->Flink;
  1255. while (p != &Connection->SendQueue) {
  1256. SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1257. if (SendIrp == Irp) {
  1258. //
  1259. // Found it, remove it from the list here.
  1260. //
  1261. RemoveEntryList (p);
  1262. Found = TRUE;
  1263. #if DBG
  1264. NbfCompletedSends[NbfCompletedSendsNext].Irp = SendIrp;
  1265. NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
  1266. NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
  1267. #endif
  1268. RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
  1269. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1270. #if DBG
  1271. DbgPrint("NBF: Canceled queued send %lx on %lx\n",
  1272. SendIrp, Connection);
  1273. #endif
  1274. //
  1275. // The following dereference will complete the I/O, provided removes
  1276. // the last reference on the request object. The I/O will complete
  1277. // with the status and information stored in the Irp. Therefore,
  1278. // we set those values here before the dereference.
  1279. //
  1280. KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
  1281. NbfCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
  1282. //
  1283. // STOP THE CONNECTION NO MATTER WHAT!!!
  1284. //
  1285. NbfStopConnection (Connection, STATUS_CANCELLED);
  1286. KeLowerIrql (oldirql1);
  1287. break;
  1288. }
  1289. #if 0
  1290. else {
  1291. if (CancelledFirstEor && (!(IRP_SEND_FLAGS(IoGetCurrentIrpStackLocation(SendIrp)) & TDI_SEND_PARTIAL))) {
  1292. CancelledFirstEor = FALSE;
  1293. }
  1294. }
  1295. #endif
  1296. p = p->Flink;
  1297. }
  1298. if (!Found) {
  1299. //
  1300. // We didn't find it!
  1301. //
  1302. #if DBG
  1303. DbgPrint("NBF: Tried to cancel send %lx on %lx, not found\n",
  1304. Irp, Connection);
  1305. #endif
  1306. RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
  1307. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1308. }
  1309. }
  1310. NbfDereferenceConnection ("Cancelling Send", Connection, CREF_COMPLETE_SEND);
  1311. }
  1312. BOOLEAN
  1313. ResendPacket (
  1314. PTP_LINK Link,
  1315. PTP_PACKET Packet
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. This routine resends a packet on the link. Since this is a resend, we
  1320. are careful to not reset the state unless all resends have completed.
  1321. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  1322. Arguments:
  1323. Link - Pointer to a TP_LINK object.
  1324. Packet - pointer to packet to be resent.
  1325. Return Value:
  1326. True if resending should continue; FALSE otherwise.
  1327. --*/
  1328. {
  1329. BOOLEAN PollFinal;
  1330. PDLC_I_FRAME DlcHeader;
  1331. UINT DataLength;
  1332. //
  1333. DlcHeader = (PDLC_I_FRAME)&(Packet->Header[Link->HeaderLength]);
  1334. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1335. NbfPrint3 ("ReSendPacket: %lx NdisPacket: %lx # %x\n",
  1336. Packet, Packet->NdisPacket,
  1337. DlcHeader->RcvSeq >>1);
  1338. IF_NBFDBG (NBF_DEBUG_PKTCONTENTS) {
  1339. {PUCHAR q;
  1340. USHORT i;
  1341. q = Packet->Header;
  1342. for (i=0;i<20;i++) {
  1343. NbfPrint1 (" %2x",q[i]);
  1344. }
  1345. NbfPrint0 ("\n");}
  1346. }
  1347. }
  1348. DataLength = Packet->NdisIFrameLength;
  1349. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1350. Link->WindowErrors++;
  1351. PollFinal = (BOOLEAN)((DlcHeader->RcvSeq & DLC_I_PF) != 0);
  1352. StopT2 (Link); // since this is potentially acking some frames
  1353. if (Link->Provider->MacInfo.MediumAsync) {
  1354. if (PollFinal) {
  1355. ASSERT (Packet->Link != NULL);
  1356. NbfReferenceLink ("ResendPacket", Link, LREF_START_T1);
  1357. } else {
  1358. StartT1 (Link, 0);
  1359. }
  1360. } else {
  1361. StartT1 (Link, PollFinal ? DataLength : 0); // restart transmission timer
  1362. }
  1363. //
  1364. // Update the expected next receive in case it's changed
  1365. //
  1366. if (PollFinal) {
  1367. DlcHeader->RcvSeq = DLC_I_PF; // set the poll bit.
  1368. Link->SendState = SEND_STATE_CHECKPOINTING;
  1369. Link->ResendingPackets = FALSE;
  1370. } else {
  1371. DlcHeader->RcvSeq = 0;
  1372. }
  1373. //
  1374. // DlcHeader->RcvSeq has Link->NextReceive inserted by NbfNdisSend.
  1375. //
  1376. NbfReferencePacket (Packet); // so we don't remove it in send completion
  1377. NbfReferenceLink ("ResendPacket", Link, LREF_NDIS_SEND);
  1378. ASSERT (Packet->PacketSent == TRUE);
  1379. Packet->PacketSent = FALSE;
  1380. //
  1381. // Update our "bytes resent" counters.
  1382. //
  1383. DataLength -=
  1384. Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
  1385. ADD_TO_LARGE_INTEGER(
  1386. &Link->Provider->Statistics.DataFrameBytesResent,
  1387. DataLength);
  1388. ++Link->Provider->Statistics.DataFramesResent;
  1389. //
  1390. // Send the packet (this release the link spinlock).
  1391. //
  1392. NbfNdisSend (Link, Packet);
  1393. ++Link->PacketsResent;
  1394. NbfDereferenceLink ("ResendPacket", Link, LREF_NDIS_SEND);
  1395. //
  1396. // if this packet has POLL set, stop the resending so the
  1397. // link doesn't get all twisted up.
  1398. //
  1399. if (PollFinal) {
  1400. //
  1401. // so we're in the state of having sent a poll and not
  1402. // sending anything else until we get a final. This avoids
  1403. // overrunning the remote. Note that we leave the routine
  1404. // with state LINK_SENDSTATE_REJECTING, which guarentees
  1405. // we won't start any new sends until we traverse through
  1406. // this routine again.
  1407. //
  1408. //
  1409. return FALSE;
  1410. }
  1411. return TRUE;
  1412. }
  1413. BOOLEAN
  1414. ResendLlcPackets (
  1415. PTP_LINK Link,
  1416. UCHAR AckSequenceNumber,
  1417. BOOLEAN Resend
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. This routine advances the state of a data link connection by retiring
  1422. all of the packets on the link's WackQ that have send sequence numbers
  1423. logically less than that number specified as the AckSequenceNumber, and
  1424. resending those above that number. The packets are disposed of by
  1425. dereferencing them. We cannot simply destroy them because this
  1426. acknowlegement might arrive even before the Physical Provider has had a
  1427. chance to issue a completion event for the associated I/O.
  1428. NOTE: This function is called with the link spinlock held and
  1429. returns with it held, but it may release it in between. THIS
  1430. ROUTINE MUST BE CALLED AT DPC LEVEL.
  1431. Arguments:
  1432. Link - Pointer to a TP_LINK object.
  1433. AckSequenceNumber - An unsigned number specifing the sequence number of
  1434. the first packet within the window that is NOT acknowleged.
  1435. Resend - if TRUE, resend packets. If FALSE, just remove them from the
  1436. wackq and get out.
  1437. Return Value:
  1438. none.
  1439. --*/
  1440. {
  1441. PTP_PACKET packet;
  1442. PLIST_ENTRY p, p1;
  1443. UCHAR packetSeq;
  1444. BOOLEAN passedAck = FALSE;
  1445. PDLC_I_FRAME DlcHeader;
  1446. SCHAR Difference;
  1447. BOOLEAN ReturnValue = FALSE;
  1448. // NDIS_STATUS ndisStatus;
  1449. //
  1450. // Move through the queue, releasing those we've been acked for and resending
  1451. // others above that.
  1452. //
  1453. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1454. NbfPrint3 ("ResendLlcPackets: Link %lx, Ack: %x, LinkLastAck: %x.\n",
  1455. Link, AckSequenceNumber, Link->LastAckReceived);
  1456. NbfPrint0 ("RLP: Walking WackQ, Packets:\n");
  1457. p = Link->WackQ.Flink; // p = ptr, 1st pkt's linkage.
  1458. while (p != &Link->WackQ) {
  1459. packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
  1460. DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
  1461. NbfPrint4 ("RLP: Pkt: %lx # %x Flags: %d %d\n", packet,
  1462. (UCHAR)(DlcHeader->SendSeq >> 1), packet->PacketSent, packet->PacketNoNdisBuffer);
  1463. p = packet->Linkage.Flink;
  1464. }
  1465. }
  1466. //
  1467. // If somebody else is resending LLC packets (which means they
  1468. // are in this function with Resend == TRUE), then ignore
  1469. // this frame. This is because it may ack a frame that he
  1470. // is in the middle of resending, which will cause problems.
  1471. //
  1472. // This isn't a great solution, we should keep track
  1473. // of where the other guy is and avoid stepping on him. This
  1474. // might mess up his walking of the queue however.
  1475. //
  1476. if (Link->ResendingPackets) {
  1477. NbfPrint1("ResendLlcPackets: Someone else resending on %lx\n", Link);
  1478. return TRUE;
  1479. }
  1480. //
  1481. // We have already checked that AckSequenceNumber is reasonable.
  1482. //
  1483. Link->LastAckReceived = AckSequenceNumber;
  1484. if (Resend) {
  1485. //
  1486. // Only one person can be resending or potentially resending
  1487. // at one time.
  1488. //
  1489. Link->ResendingPackets = TRUE;
  1490. }
  1491. //
  1492. // Resend as many packets as we have window to send. We spin through the
  1493. // queue and remove those packets that have been acked or that are
  1494. // sequence numbered logically below the current ack number. The flags
  1495. // PACKET_FLAGS_RESEND and PACKET_FLAGS_SENT correspond to the three states
  1496. // a packet on this queue can be in:
  1497. //
  1498. // 1) if _RESEND is set, the packet has not been acked
  1499. //
  1500. // 2) if _SENT is set, the packet send has completed (conversely, if NOT
  1501. // set, the packet has not yet been completely sent, thus it is
  1502. // unnecessary to resend it).
  1503. // 3) if _RESEND and _SENT are both set, the packet has been sent and not
  1504. // acked and is grist for our mills.
  1505. // 4) if neither is set, the world is coming to an end next Thursday.
  1506. //
  1507. p=Link->WackQ.Flink;
  1508. while (p != &Link->WackQ) {
  1509. packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
  1510. DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
  1511. //
  1512. // if both bits aren't set we can't do a thing with this packet, or,
  1513. // for that matter, with the rest of the packet list. We can't
  1514. // have reached the ack number yet, as these packets haven't even
  1515. // completed sending.
  1516. // (Later) actually, we can have reached passedAck, and if we did
  1517. // we're in a world of hurt. We can't send more regular packets,
  1518. // but we can't send any resend packets either. Force the link to
  1519. // checkpoint and things will clear themselves up later.
  1520. //
  1521. if (!(packet->PacketSent)) {
  1522. if (passedAck) {
  1523. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1524. NbfPrint2 ("ResendLLCPacket: Can't send WACKQ Packet RcvSeq %x %x \n",
  1525. DlcHeader->RcvSeq, DlcHeader->SendSeq);
  1526. }
  1527. if (Link->SendState != SEND_STATE_CHECKPOINTING) {
  1528. //
  1529. // Don't start checkpointing if we already are.
  1530. //
  1531. Link->SendState = SEND_STATE_CHECKPOINTING;
  1532. StopTi (Link);
  1533. StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // start checkpoint timeout.
  1534. Link->ResendingPackets = FALSE;
  1535. //
  1536. // Try this...in this case don't actually send
  1537. // an RR, since his response might put us right
  1538. // back here. When T1 expires we will recover.
  1539. //
  1540. // NbfSendRr (Link, TRUE, TRUE);
  1541. } else {
  1542. Link->ResendingPackets = FALSE;
  1543. }
  1544. return TRUE;
  1545. }
  1546. //
  1547. // Don't break, since passedAck is FALSE all we will
  1548. // do in the next section is TpDereferencePacket, which
  1549. // is correct.
  1550. //
  1551. // break;
  1552. }
  1553. //
  1554. // This loop is somewhat schizo; at this point, if we've not yet reached
  1555. // the ack number, we'll be ditching the packet. If we've gone through
  1556. // the ack number, we'll be re-transmitting. Note that in the first
  1557. // personality, we are always looking at the beginning of the list.
  1558. //
  1559. //
  1560. // NOTE: Link spinlock is held here.
  1561. //
  1562. packetSeq = (UCHAR)(DlcHeader->SendSeq >> 1);
  1563. if (!passedAck){
  1564. //
  1565. // Compute the signed difference here; see if
  1566. // packetSeq is equal to or "greater than"
  1567. // LastAckReceived.
  1568. //
  1569. Difference = packetSeq - Link->LastAckReceived;
  1570. if (((Difference >= 0) && (Difference < 0x40)) ||
  1571. (Difference < -0x40)) {
  1572. //
  1573. // We have found a packet on the queue that was
  1574. // not acknowledged by LastAckReceived.
  1575. //
  1576. if (Link->SendState == SEND_STATE_CHECKPOINTING) {
  1577. //
  1578. // If we are checkpointing, we should not do any of
  1579. // the passedAck things (i.e. any of the things which
  1580. // potentially involve sending packets) - adb 7/30/91.
  1581. //
  1582. if (Resend) {
  1583. Link->ResendingPackets = FALSE;
  1584. }
  1585. return TRUE;
  1586. }
  1587. if (!Resend) {
  1588. //
  1589. // If we are not supposed to resend, then exit.
  1590. // Since there are still packets on the queue
  1591. // we restart T1.
  1592. //
  1593. StopTi (Link);
  1594. StartT1 (Link, 0); // start checkpoint timeout.
  1595. return TRUE;
  1596. }
  1597. //
  1598. // Lock out senders, so we maintain packet sequences properly
  1599. //
  1600. Link->SendState = SEND_STATE_REJECTING; // we're resending.
  1601. passedAck = TRUE;
  1602. //
  1603. // Note that we don't advance the pointer to the next packet;
  1604. // thus, we will resend this packet on the next pass through
  1605. // the while loop (taking the passedAck branch).
  1606. //
  1607. } else {
  1608. p1 = RemoveHeadList (&Link->WackQ);
  1609. ASSERTMSG (" ResendLLCPacket: Packet not at queue head!\n", (p == p1));
  1610. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1611. ReturnValue = TRUE;
  1612. NbfDereferencePacket (packet);
  1613. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1614. p = Link->WackQ.Flink;
  1615. }
  1616. } else {
  1617. // NbfPrint1 ("RLP: # %x\n",packetSeq);
  1618. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1619. //
  1620. // If this call returns FALSE (because we checkpoint)
  1621. // it clears ResendingPacket before it returns.
  1622. //
  1623. if (!ResendPacket (Link, packet)) {
  1624. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1625. return ReturnValue;
  1626. }
  1627. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1628. p = p->Flink;
  1629. }
  1630. }
  1631. //
  1632. // NOTE: Link spinlock is held here.
  1633. //
  1634. if (passedAck) {
  1635. //
  1636. // If we exit through here with passedAck TRUE, it means that we
  1637. // successfully called ResendPacket on every packet in the
  1638. // WackQ, which means we did not resend a poll packet, so we
  1639. // can start sending normally again. We have to clear
  1640. // ResendingPackets here.
  1641. //
  1642. Link->SendState = SEND_STATE_READY;
  1643. Link->ResendingPackets = FALSE;
  1644. StartTi (Link);
  1645. } else if (!Resend) {
  1646. //
  1647. // If Resend is FALSE (in which case passedAck will also be FALSE,
  1648. // by the way), and the WackQ is empty, that means that we
  1649. // successfully acknowledged all the packets on a non-final
  1650. // frame. In this case T1 may be running, but in fact is not
  1651. // needed since there are no sends outstanding.
  1652. //
  1653. if (Link->WackQ.Flink == &Link->WackQ) {
  1654. StopT1 (Link);
  1655. }
  1656. Link->SendState = SEND_STATE_READY;
  1657. StartTi (Link);
  1658. } else {
  1659. //
  1660. // Resend is TRUE, but passedAck is FALSE; we came in
  1661. // expecting to resend, but didn't. This means that
  1662. // we have emptied the queue after receiving an
  1663. // RR/f, i.e. this send window is done and we can
  1664. // update our send window size, etc.
  1665. //
  1666. Link->ResendingPackets = FALSE;
  1667. if (Link->Provider->MacInfo.MediumAsync) {
  1668. return ReturnValue;
  1669. }
  1670. if (Link->WindowErrors > 0) {
  1671. //
  1672. // We had transmit errors on this window.
  1673. //
  1674. Link->PrevWindowSize = Link->SendWindowSize;
  1675. //
  1676. // We use 100 ms delay as the cutoff for a LAN.
  1677. //
  1678. if (Link->Delay < (100*MILLISECONDS)) {
  1679. //
  1680. // On a LAN, if we have a special case
  1681. // if one packet was lost; this means the
  1682. // final packet was retransmitted once. In
  1683. // that case, we keep track of Consecutive
  1684. // LastPacketLost, and if it reaches 2, then
  1685. // we lock the send window at its current
  1686. // value minus one.
  1687. //
  1688. if (Link->WindowErrors == 1) {
  1689. ++Link->ConsecutiveLastPacketLost;
  1690. if (Link->ConsecutiveLastPacketLost >= 2) {
  1691. //
  1692. // Freeze the window wherever it was.
  1693. //
  1694. if (Link->SendWindowSize > Link->Provider->MinimumSendWindowLimit) {
  1695. Link->MaxWindowSize = Link->SendWindowSize - 1;
  1696. Link->SendWindowSize = (UCHAR)Link->MaxWindowSize;
  1697. }
  1698. }
  1699. //
  1700. // Otherwise, we leave the window where it is.
  1701. //
  1702. } else {
  1703. Link->ConsecutiveLastPacketLost = 0;
  1704. Link->SendWindowSize -= (UCHAR)Link->WindowErrors;
  1705. }
  1706. } else {
  1707. //
  1708. // On a WAN we cut the send window in half,
  1709. // regardless of how many frames were retransmitted.
  1710. //
  1711. Link->SendWindowSize /= 2;
  1712. Link->WindowsUntilIncrease = 1; // in case Prev is also 1.
  1713. Link->ConsecutiveLastPacketLost = 0;
  1714. }
  1715. if ((SCHAR)Link->SendWindowSize < 1) {
  1716. Link->SendWindowSize = 1;
  1717. }
  1718. //
  1719. // Reset our counters for the next window.
  1720. //
  1721. Link->WindowErrors = 0;
  1722. } else {
  1723. //
  1724. // We have successfully sent a window of data, increase
  1725. // the send window size unless we are at the limit.
  1726. // We use 100 ms delay as the WAN/LAN cutoff.
  1727. //
  1728. if ((ULONG)Link->SendWindowSize < Link->MaxWindowSize) {
  1729. if (Link->Delay < (100*MILLISECONDS)) {
  1730. //
  1731. // On a LAN, increase the send window by 1.
  1732. //
  1733. // Need to determine optimal window size.
  1734. //
  1735. Link->SendWindowSize++;
  1736. } else {
  1737. //
  1738. // On a WAN, increase the send window by 1 until
  1739. // we hit PrevWindowSize, then do it more slowly.
  1740. //
  1741. if (Link->SendWindowSize < Link->PrevWindowSize) {
  1742. Link->SendWindowSize++;
  1743. //
  1744. // If we just increased it to the previous window
  1745. // size, prepare for the next time through here.
  1746. //
  1747. if (Link->SendWindowSize == Link->PrevWindowSize) {
  1748. Link->WindowsUntilIncrease = Link->SendWindowSize;
  1749. }
  1750. } else {
  1751. //
  1752. // We passed the previous size, so only update every
  1753. // WindowsUntilIncrease times.
  1754. //
  1755. if (--Link->WindowsUntilIncrease == 0) {
  1756. Link->SendWindowSize++;
  1757. Link->WindowsUntilIncrease = Link->SendWindowSize;
  1758. }
  1759. }
  1760. }
  1761. if ((ULONG)Link->SendWindowSize > Link->Provider->Statistics.MaximumSendWindow) {
  1762. Link->Provider->Statistics.MaximumSendWindow = Link->SendWindowSize;
  1763. }
  1764. }
  1765. //
  1766. // Clear this since we had no errors.
  1767. //
  1768. Link->ConsecutiveLastPacketLost = 0;
  1769. }
  1770. }
  1771. return ReturnValue;
  1772. } /* ResendLlcPackets */
  1773. VOID
  1774. NbfSendCompletionHandler(
  1775. IN NDIS_HANDLE ProtocolBindingContext,
  1776. IN PNDIS_PACKET NdisPacket,
  1777. IN NDIS_STATUS NdisStatus
  1778. )
  1779. /*++
  1780. Routine Description:
  1781. This routine is called by the I/O system to indicate that a connection-
  1782. oriented packet has been shipped and is no longer needed by the Physical
  1783. Provider.
  1784. Arguments:
  1785. NdisContext - the value associated with the adapter binding at adapter
  1786. open time (which adapter we're talking on).
  1787. NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
  1788. NdisStatus - the completion status of the send.
  1789. Return Value:
  1790. none.
  1791. --*/
  1792. {
  1793. PSEND_PACKET_TAG SendContext;
  1794. PTP_PACKET Packet;
  1795. KIRQL oldirql1;
  1796. ProtocolBindingContext; // avoid compiler warnings
  1797. #if DBG
  1798. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  1799. NbfSendsCompletedAfterPendFail++;
  1800. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1801. NbfPrint2 ("NbfSendComplete: Entered for packet %lx, Status %s\n",
  1802. NdisPacket, NbfGetNdisStatus (NdisStatus));
  1803. }
  1804. } else {
  1805. NbfSendsCompletedAfterPendOk++;
  1806. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1807. NbfPrint2 ("NbfSendComplete: Entered for packet %lx, Status %s\n",
  1808. NdisPacket, NbfGetNdisStatus (NdisStatus));
  1809. }
  1810. }
  1811. #endif
  1812. SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0];
  1813. switch (SendContext->Type) {
  1814. case TYPE_I_FRAME:
  1815. //
  1816. // Just dereference the packet. There are a couple possibilities here.
  1817. // First, the I/O completion might happen before an ACK is received,
  1818. // in which case this will remove one of the references, but not both.
  1819. // Second, the LLC ACK for this packet may have already been processed,
  1820. // in which case this will destroy the packet. Third, this packet may
  1821. // be resent, either before or after this call, in which case the deref
  1822. // won't destroy the packet.
  1823. //
  1824. // NbfDereferencePacket will call PacketizeSend if it determines that
  1825. // there is at least one connection waiting to be packetized because
  1826. // of out-of-resource conditions or because its window has been opened.
  1827. //
  1828. Packet = ((PTP_PACKET)SendContext->Frame);
  1829. KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
  1830. if (Packet->Provider->MacInfo.MediumAsync) {
  1831. if (Packet->Link) {
  1832. ASSERT (Packet->NdisIFrameLength > 0);
  1833. ACQUIRE_DPC_SPIN_LOCK (&Packet->Link->SpinLock);
  1834. StartT1 (Packet->Link, Packet->NdisIFrameLength);
  1835. RELEASE_DPC_SPIN_LOCK (&Packet->Link->SpinLock);
  1836. NbfDereferenceLink ("Send completed", Packet->Link, LREF_START_T1);
  1837. }
  1838. if (Packet->PacketizeConnection) {
  1839. PTP_CONNECTION Connection = IRP_SEND_CONNECTION((PIO_STACK_LOCATION)(Packet->Owner));
  1840. PDEVICE_CONTEXT DeviceContext = Packet->Provider;
  1841. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1842. if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
  1843. (Connection->Flags & CONNECTION_FLAGS_READY)) {
  1844. ASSERT (Connection->Flags & CONNECTION_FLAGS_PACKETIZE);
  1845. ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->SpinLock);
  1846. NbfReferenceConnection ("Delayed packetizing", Connection, CREF_PACKETIZE_QUEUE);
  1847. InsertTailList(&DeviceContext->PacketizeQueue, &Connection->PacketizeLinkage);
  1848. if (!DeviceContext->WanThreadQueued) {
  1849. DeviceContext->WanThreadQueued = TRUE;
  1850. ExQueueWorkItem(&DeviceContext->WanDelayedQueueItem, DelayedWorkQueue);
  1851. }
  1852. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1853. } else {
  1854. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  1855. }
  1856. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1857. NbfDereferenceConnection ("PacketizeConnection FALSE", Connection, CREF_TEMP);
  1858. Packet->PacketizeConnection = FALSE;
  1859. }
  1860. }
  1861. #if DBG
  1862. if (Packet->PacketSent) {
  1863. DbgPrint ("NbfSendCompletionHandler: Packet %lx already completed\n", Packet);
  1864. DbgBreakPoint();
  1865. }
  1866. #endif
  1867. Packet->PacketSent = TRUE;
  1868. NbfDereferencePacket (Packet);
  1869. KeLowerIrql (oldirql1);
  1870. break;
  1871. case TYPE_UI_FRAME:
  1872. //
  1873. // just destroy the frame; name stuff doesn't depend on having any
  1874. // of the sent message left around after the send completed.
  1875. //
  1876. NbfDestroyConnectionlessFrame ((PDEVICE_CONTEXT)SendContext->Owner,
  1877. (PTP_UI_FRAME)SendContext->Frame);
  1878. break;
  1879. case TYPE_ADDRESS_FRAME:
  1880. //
  1881. // Addresses get their own frames; let the address know it's ok to
  1882. // use the frame again.
  1883. //
  1884. NbfSendDatagramCompletion ((PTP_ADDRESS)SendContext->Owner,
  1885. NdisPacket,
  1886. NdisStatus );
  1887. break;
  1888. }
  1889. return;
  1890. } /* NbfSendCompletionHandler */
  1891. NTSTATUS
  1892. SendOnePacket(
  1893. IN PTP_CONNECTION Connection,
  1894. IN PTP_PACKET Packet,
  1895. IN BOOLEAN ForceAck,
  1896. OUT PBOOLEAN LinkCheckpoint OPTIONAL
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. This routine sends a connection-oriented packet by calling the NDIS
  1901. Send service. At least one event will occur following
  1902. (or during) the Send request's processing. (1) The Send request
  1903. will complete through the I/O system, calling IoCompleteRequest.
  1904. (2) The sequenced packet will be acknowleged at the LLC level, or it
  1905. will be rejected and reset at the LLC level. If the packet is resent,
  1906. then it remains queued at the TP_LINK object. If the packet is ACKed,
  1907. then is removed from the link's WackQ and the Action field in the
  1908. TP_PACKET structure dictates what operation to perform next.
  1909. NOTE: This routine is called with the link spinlock held. THIS
  1910. ROUTINE MUST BE CALLED AT DPC LEVEL.
  1911. NOTE: This routine will now accept all frames unless the link
  1912. is down. If the link cannot send, the packet will be queued and
  1913. sent when possible.
  1914. Arguments:
  1915. Connection - Pointer to a TP_CONNECTION object.
  1916. Packet - Pointer to a TP_PACKET object.
  1917. ForceAck - Boolean that, if true, indicates this packet should always have
  1918. the Poll bit set; this force the other side to ack immediately,
  1919. which is necessary for correct session teardown.
  1920. LinkCheckpoint - If specified, will return TRUE if the link has
  1921. just entered a checkpoint state. In this case the status
  1922. will be STATUS_SUCCESS, but the connection should stop
  1923. packetizing now (in fact, to close a window, the connection
  1924. is put into the W_LINK state if this status will be
  1925. returned, so he must stop because somebody else may
  1926. already be doing it).
  1927. Return Value:
  1928. STATUS_LINK_FAILED - the link is dead or not ready.
  1929. STATUS_SUCCESS - the packet has been sent.
  1930. STATUS_INSUFFICIENT_RESOURCES - the packet has been queued.
  1931. --*/
  1932. {
  1933. PTP_LINK Link;
  1934. PDLC_I_FRAME DlcHeader;
  1935. PNDIS_BUFFER ndisBuffer;
  1936. ULONG SendsOutstanding;
  1937. BOOLEAN Poll = FALSE;
  1938. NTSTATUS Status;
  1939. IF_NBFDBG (NBF_DEBUG_PACKET) {
  1940. NbfPrint3 ("SendOnePacket: Entered, connection %lx, packet %lx DnisPacket %lx.\n",
  1941. Connection, Packet, Packet->NdisPacket);
  1942. }
  1943. Link = Connection->Link;
  1944. IF_NBFDBG (NBF_DEBUG_PACKET) {
  1945. UINT PLength, PCount;
  1946. UINT BLength;
  1947. PVOID BAddr;
  1948. NdisQueryPacket(Packet->NdisPacket, &PCount, NULL, &ndisBuffer, &PLength);
  1949. NbfPrint3 ("Sending Data Packet: %lx, Length: %lx Pages: %lx\n",
  1950. Packet->NdisPacket, PLength, PCount);
  1951. while (ndisBuffer != NULL) {
  1952. NdisQueryBuffer(ndisBuffer, &BAddr, &BLength);
  1953. NbfPrint3 ("Sending Data Packet: Buffer %08lx Length %08lx Va %08lx\n",
  1954. ndisBuffer, BLength, BAddr);
  1955. NdisGetNextBuffer (ndisBuffer, &ndisBuffer);
  1956. }
  1957. }
  1958. //
  1959. // If the general state of the link is not READY, then we can't ship.
  1960. // This failure can be expected under some conditions, and may not cause
  1961. // failure of the send.
  1962. //
  1963. if (Link->State != LINK_STATE_READY) {
  1964. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1965. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1966. NbfPrint1 ("SendOnePacket: Link state is not READY (%ld).\n", Link->State);
  1967. }
  1968. //
  1969. // determine what to do with this problem. If we shouldn't be sending
  1970. // here, percolate an error upward.
  1971. //
  1972. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  1973. NbfPrint3 ("SendOnePacket: Link Bad state, link: %lx Link Flags %lx Link State %lx\n",
  1974. Link, Link->Flags, Link->State);
  1975. }
  1976. return STATUS_LINK_FAILED;
  1977. }
  1978. SendsOutstanding = (((ULONG)Link->NextSend+128L-(ULONG)Link->LastAckReceived)%128L);
  1979. //
  1980. // Format LLC header while we've got the spinlock to atomically update
  1981. // the link's state information.
  1982. //
  1983. DlcHeader = (PDLC_I_FRAME)&(Packet->Header[Link->HeaderLength]);
  1984. DlcHeader->SendSeq = (UCHAR)(Link->NextSend << 1);
  1985. Link->NextSend = (UCHAR)((Link->NextSend + 1) & 0x7f);
  1986. DlcHeader->RcvSeq = 0; // Link->NextReceive is inserted by NbfNdisSend
  1987. //
  1988. // Before we release the spinlock, we append the packet to the
  1989. // end of the link's WackQ, so that if an ACK arrives before the NdisSend
  1990. // completes, it will be on the queue already. Also, mark the packet as
  1991. // needing resend, which is canceled by AckLLCPackets, and used by
  1992. // ResendLLCPackets. Thus, all packets will need to be resent until they
  1993. // are acked.
  1994. //
  1995. ASSERT (Packet->PacketSent == FALSE);
  1996. InsertTailList (&Link->WackQ, &Packet->Linkage);
  1997. //SrvCheckListIntegrity( &Link->WackQ, 200 );
  1998. //
  1999. // If the send state is not READY, we can't ship.
  2000. // This failure is mostly caused by flow control or retransmit in progress,
  2001. // and is never cause for failure of the send.
  2002. //
  2003. if ((Link->SendState != SEND_STATE_READY) ||
  2004. (Link->LinkBusy) ||
  2005. (SendsOutstanding >= (ULONG)Link->SendWindowSize)) {
  2006. if ((Link->SendWindowSize == 1) || ForceAck) {
  2007. DlcHeader->RcvSeq |= DLC_I_PF; // set the poll bit.
  2008. if (Link->Provider->MacInfo.MediumAsync) {
  2009. Packet->Link = Link;
  2010. }
  2011. }
  2012. Packet->PacketSent = TRUE; // allows it to be resent.
  2013. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  2014. #if DBG
  2015. if (Link->SendState != SEND_STATE_READY) {
  2016. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2017. NbfPrint1 ("SendOnePacket: Link send state not READY (%ld).\n", Link->SendState);
  2018. }
  2019. } else if (Link->LinkBusy) {
  2020. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2021. PANIC ("SendOnePacket: Link is busy.\n");
  2022. }
  2023. } else if (SendsOutstanding >= (ULONG)Link->SendWindowSize) {
  2024. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2025. NbfPrint3 ("SendOnePacket: No link send window; N(S)=%ld,LAR=%ld,SW=%ld.\n",
  2026. Link->NextSend, Link->LastAckReceived, Link->SendWindowSize);
  2027. }
  2028. }
  2029. #endif
  2030. return STATUS_INSUFFICIENT_RESOURCES;
  2031. }
  2032. //
  2033. // Reference the packet since it is given to the NDIS driver.
  2034. //
  2035. #if DBG
  2036. NbfReferencePacket (Packet);
  2037. #else
  2038. ++Packet->ReferenceCount; // OK since it is not queued anywhere.
  2039. #endif
  2040. //
  2041. // If this is the last I-frame in the window, then indicate that we
  2042. // should checkpoint. Also checkpoint if the sender is requesting
  2043. // acknowledgement (currently on SendSessionEnd does this).
  2044. // By default, this will also be a command frame.
  2045. //
  2046. if (((SendsOutstanding+1) >= (ULONG)Link->SendWindowSize) ||
  2047. ForceAck) {
  2048. Link->SendState = SEND_STATE_CHECKPOINTING;
  2049. StopTi (Link);
  2050. DlcHeader->RcvSeq |= DLC_I_PF; // set the poll bit.
  2051. Poll = TRUE;
  2052. }
  2053. //
  2054. // If we are polling, and the caller cares about it, then
  2055. // we set LinkCheckpoint, and also set up the connection to
  2056. // be waiting for resources. We do this now, before the send,
  2057. // so that even if the ack is receive right away, we will
  2058. // be in a good state. When we return LinkCheckpoint TRUE
  2059. // the caller realizes that he no longer owns the right
  2060. // to "packetize" and exits immediately.
  2061. //
  2062. // We also want to start our retransmission timer so, if this
  2063. // packet gets dropped, we will know to retransmit it. The
  2064. // exception is if LinkCheckpoint was specified, then we
  2065. // only StartT1 of we are not polling (the caller will
  2066. // ensure it is started if he exits before we poll).
  2067. //
  2068. if (ARGUMENT_PRESENT(LinkCheckpoint)) {
  2069. if (Poll) {
  2070. //
  2071. // If the connection still has send state PACKETIZE,
  2072. // then change it to W_LINK. If it is something else
  2073. // (such as W_PACKET or W_ACK) then don't worry, when
  2074. // that condition clears he will repacketize and the
  2075. // link conditions will be re-examined. In all
  2076. // case we turn off the PACKETIZE flag, because when
  2077. // we return with LinkCheckpoint TRUE he will stop
  2078. // packetizing, and to close the window we turn it
  2079. // off now (before the NdisSend) rather than then.
  2080. //
  2081. ASSERT (Connection->LinkSpinLock == &Link->SpinLock);
  2082. if (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) {
  2083. Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
  2084. }
  2085. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  2086. if (Link->Provider->MacInfo.MediumAsync) {
  2087. Packet->Link = Link;
  2088. NbfReferenceLink ("Send I-frame", Link, LREF_START_T1);
  2089. } else {
  2090. StartT1 (Link, Packet->NdisIFrameLength);
  2091. }
  2092. *LinkCheckpoint = TRUE;
  2093. } else {
  2094. StartT1 (Link, 0);
  2095. *LinkCheckpoint = FALSE;
  2096. }
  2097. } else {
  2098. //
  2099. // If LinkCheckpoint is not true, then we are sending
  2100. // an I-frame other than DFM/DOL. In this case, as
  2101. // an optimization, we'll set W_LINK if a) we are
  2102. // polling b) we are IDLE (to avoid messing up other
  2103. // states such as W_ACK). This will avoid a window
  2104. // where we don't go W_LINK until after the next
  2105. // send tries to packetize and fails.
  2106. //
  2107. if (Poll) {
  2108. ASSERT (Connection->LinkSpinLock == &Link->SpinLock);
  2109. if (Connection->SendState == CONNECTION_SENDSTATE_IDLE) {
  2110. Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
  2111. }
  2112. }
  2113. //
  2114. // This is an optimization; we know that if LinkCheckpoint
  2115. // is present than we are being called from PacketizeSend;
  2116. // in this case the Link will have the LREF_CONNECTION
  2117. // reference and the connection will have the CREF_PACKETIZE
  2118. // reference, so we don't have to reference the link
  2119. // again.
  2120. //
  2121. NbfReferenceLink ("SendOnePacket", Link, LREF_NDIS_SEND);
  2122. //
  2123. // Start the retransmission timer.
  2124. //
  2125. if (Link->Provider->MacInfo.MediumAsync) {
  2126. if (Poll) {
  2127. Packet->Link = Link;
  2128. NbfReferenceLink ("ResendPacket", Link, LREF_START_T1);
  2129. } else {
  2130. StartT1 (Link, 0);
  2131. }
  2132. } else {
  2133. StartT1 (Link, Poll ? Packet->NdisIFrameLength : 0);
  2134. }
  2135. }
  2136. //
  2137. // Since this I-frame contains an N(R), it is potentially ACKing some
  2138. // previously received I-frames as reverse traffic. So we stop our
  2139. // delayed acknowlegement timer.
  2140. //
  2141. StopT2 (Link);
  2142. if ((Link->Provider->MacInfo.MediumAsync) &&
  2143. (ARGUMENT_PRESENT(LinkCheckpoint)) &&
  2144. (Link->SendWindowSize >= 3) &&
  2145. (!Poll) && (SendsOutstanding == (ULONG)(Link->SendWindowSize-2))) {
  2146. Status = STATUS_MORE_PROCESSING_REQUIRED;
  2147. Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
  2148. NbfReferenceConnection ("PacketizeConnection TRUE", Connection, CREF_TEMP);
  2149. Packet->PacketizeConnection = TRUE;
  2150. } else {
  2151. Status = STATUS_SUCCESS;
  2152. }
  2153. //
  2154. // Send the packet; no locks held. Note that if the send fails, we will
  2155. // NOT fail upward; we allow things to continue onward. This lets us retry
  2156. // the send multiple times before we give out; additionally, it keeps us
  2157. // from failing obscurely when sending control Iframes.
  2158. //
  2159. // NOTE: NbfNdisSend releases the link spinlock.
  2160. //
  2161. NbfNdisSend (Link, Packet);
  2162. Link->PacketsSent++;
  2163. //
  2164. // Remove the reference made above if needed.
  2165. //
  2166. if (!ARGUMENT_PRESENT(LinkCheckpoint)) {
  2167. NbfDereferenceLink ("SendOnePacket", Link, LREF_NDIS_SEND);
  2168. }
  2169. return Status;
  2170. } /* SendOnePacket */
  2171. VOID
  2172. SendControlPacket(
  2173. IN PTP_LINK Link,
  2174. IN PTP_PACKET Packet
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. This routine sends a connection-oriented packet by calling the Physical
  2179. Provider's Send service. While SendOnePacket is used to send an I-
  2180. frame, this routine is used to send one of the following: RR, RNR, REJ,
  2181. SABME, UA, DISC, DM, FRMR, TEST, and XID.
  2182. NOTE: This function is called with the link spinlock held,
  2183. and returns with it released. IT MUST BE CALLED AT DPC LEVEL.
  2184. Arguments:
  2185. Link - Pointer to a TP_LINK object.
  2186. Packet - Pointer to a TP_PACKET object.
  2187. Return Value:
  2188. NTSTATUS - status of operation.
  2189. --*/
  2190. {
  2191. USHORT i;
  2192. PUCHAR p;
  2193. PNDIS_BUFFER ndisBuffer;
  2194. IF_NBFDBG (NBF_DEBUG_PACKET) {
  2195. NbfPrint3 ("SendControlPacket: Entered for link %lx, packet %lx, NdisPacket %lx\n 00:",
  2196. Link, Packet, Packet->NdisPacket);
  2197. IF_NBFDBG (NBF_DEBUG_PKTCONTENTS) {
  2198. UINT PLength, PCount;
  2199. UINT BLength;
  2200. PVOID BAddr;
  2201. p = Packet->Header;
  2202. for (i=0;i<20;i++) {
  2203. NbfPrint1 (" %2x",p[i]);
  2204. }
  2205. NbfPrint0 ("\n");
  2206. NdisQueryPacket(Packet->NdisPacket, &PCount, NULL, &ndisBuffer, &PLength);
  2207. NbfPrint3 ("Sending Control Packet: %lx, Length: %lx Pages: %lx\n",
  2208. Packet->NdisPacket, PLength, PCount);
  2209. while (ndisBuffer != NULL) {
  2210. NdisQueryBuffer (ndisBuffer, &BAddr, &BLength);
  2211. NbfPrint3 ("Sending Control Packet: Buffer %08lx Length %08lx Va %08lx\n",
  2212. ndisBuffer, BLength, BAddr);
  2213. NdisGetNextBuffer (ndisBuffer, &ndisBuffer);
  2214. }
  2215. }
  2216. }
  2217. ASSERT (Packet->PacketSent == FALSE);
  2218. NbfReferenceLink ("SendControlPacket", Link, LREF_NDIS_SEND);
  2219. //
  2220. // Send the packet (we have the lock, NbfNdisSend released
  2221. // it.
  2222. //
  2223. NbfNdisSend (Link, Packet);
  2224. NbfDereferenceLink ("SendControlPacket", Link, LREF_NDIS_SEND);
  2225. } /* SendControlPacket */
  2226. VOID
  2227. NbfNdisSend(
  2228. IN PTP_LINK Link,
  2229. IN PTP_PACKET Packet
  2230. )
  2231. /*++
  2232. Routine Description:
  2233. This routine is used to ensure that receive sequence numbers on
  2234. packets are numbered correctly. It is called in place of NdisSend
  2235. and after assigning the receive sequence number it locks out other
  2236. sends until the NdisSend call has returned (not necessarily completed),
  2237. insuring that the packets with increasing receive sequence numbers
  2238. are queue in the right order by the MAC.
  2239. NOTE: This routine is called with the link spinlock held,
  2240. and it returns with it released. THIS ROUTINE MUST BE CALLED
  2241. AT DPC LEVEL.
  2242. Arguments:
  2243. Link - Pointer to a TP_LINK object.
  2244. Packet - Pointer to a TP_PACKET object.
  2245. Return Value:
  2246. None.
  2247. --*/
  2248. {
  2249. NDIS_STATUS NdisStatus;
  2250. PLIST_ENTRY p;
  2251. PDLC_S_FRAME DlcHeader;
  2252. PNDIS_PACKET TmpNdisPacket;
  2253. ULONG result;
  2254. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  2255. if (Link->Provider->UniProcessor) {
  2256. //
  2257. // On a uni-processor, we can send without fear of
  2258. // being interrupted by an incoming packet.
  2259. //
  2260. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  2261. DlcHeader = (PDLC_S_FRAME)&(Packet->Header[Link->HeaderLength]);
  2262. if ((DlcHeader->Command & DLC_U_INDICATOR) != DLC_U_INDICATOR) {
  2263. //
  2264. // It's not a U-frame, so we assign RcvSeq.
  2265. //
  2266. DlcHeader->RcvSeq |= (UCHAR)(Link->NextReceive << 1);
  2267. }
  2268. #if DBG
  2269. NbfSendsIssued++;
  2270. #endif
  2271. INCREMENT_COUNTER (Link->Provider, PacketsSent);
  2272. #if PKT_LOG
  2273. // Log this packet in connection's sent packets' queue
  2274. NbfLogSndPacket(Link, Packet);
  2275. #endif // PKT_LOG
  2276. if (Link->Loopback) {
  2277. //
  2278. // This packet is sent to ourselves; we should loop it
  2279. // back.
  2280. //
  2281. NbfInsertInLoopbackQueue(
  2282. Link->Provider,
  2283. Packet->NdisPacket,
  2284. Link->LoopbackDestinationIndex
  2285. );
  2286. NdisStatus = NDIS_STATUS_PENDING;
  2287. } else {
  2288. if (Link->Provider->NdisBindingHandle) {
  2289. NdisSend (
  2290. &NdisStatus,
  2291. Link->Provider->NdisBindingHandle,
  2292. Packet->NdisPacket);
  2293. }
  2294. else {
  2295. NdisStatus = STATUS_INVALID_DEVICE_STATE;
  2296. }
  2297. }
  2298. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2299. NbfPrint1 ("NbfNdisSend: NdisSend completed Status: %s.\n",
  2300. NbfGetNdisStatus(NdisStatus));
  2301. }
  2302. switch (NdisStatus) {
  2303. case NDIS_STATUS_PENDING:
  2304. #if DBG
  2305. NbfSendsPended++;
  2306. #endif
  2307. break;
  2308. case NDIS_STATUS_SUCCESS:
  2309. #if DBG
  2310. NbfSendsCompletedInline++;
  2311. NbfSendsCompletedOk++;
  2312. #endif
  2313. NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
  2314. Packet->NdisPacket,
  2315. NDIS_STATUS_SUCCESS);
  2316. break;
  2317. default:
  2318. #if DBG
  2319. NbfSendsCompletedInline++;
  2320. NbfSendsCompletedFail++;
  2321. #endif
  2322. NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
  2323. Packet->NdisPacket,
  2324. NDIS_STATUS_SUCCESS);
  2325. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2326. NbfPrint1 ("NbfNdisSend failed, status not Pending or Complete: %lx.\n",
  2327. NbfGetNdisStatus (NdisStatus));
  2328. }
  2329. break;
  2330. }
  2331. } else {
  2332. //
  2333. // If there is a send in progress, then queue this packet
  2334. // and return.
  2335. //
  2336. if (Link->NdisSendsInProgress > 0) {
  2337. p = (PLIST_ENTRY)(Packet->NdisPacket->MacReserved);
  2338. InsertTailList (&Link->NdisSendQueue, p);
  2339. ++Link->NdisSendsInProgress;
  2340. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  2341. return;
  2342. }
  2343. //
  2344. // No send in progress. Set the flag to true, and fill in the
  2345. // receive sequence field in the packet (note that the RcvSeq
  2346. // field is in the same place for I- and S-frames.
  2347. //
  2348. Link->NdisSendsInProgress = 1;
  2349. while (TRUE) {
  2350. DlcHeader = (PDLC_S_FRAME)&(Packet->Header[Link->HeaderLength]);
  2351. if ((DlcHeader->Command & DLC_U_INDICATOR) != DLC_U_INDICATOR) {
  2352. //
  2353. // It's not a U-frame, so we assign RcvSeq.
  2354. //
  2355. DlcHeader->RcvSeq |= (UCHAR)(Link->NextReceive << 1);
  2356. }
  2357. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  2358. #if DBG
  2359. NbfSendsIssued++;
  2360. #endif
  2361. INCREMENT_COUNTER (Link->Provider, PacketsSent);
  2362. #if PKT_LOG
  2363. // Log this packet in connection's sent packets' queue
  2364. NbfLogSndPacket(Link, Packet);
  2365. #endif // PKT_LOG
  2366. if (Link->Loopback) {
  2367. //
  2368. // This packet is sent to ourselves; we should loop it
  2369. // back.
  2370. //
  2371. NbfInsertInLoopbackQueue(
  2372. Link->Provider,
  2373. Packet->NdisPacket,
  2374. Link->LoopbackDestinationIndex
  2375. );
  2376. NdisStatus = NDIS_STATUS_PENDING;
  2377. } else {
  2378. if (Link->Provider->NdisBindingHandle) {
  2379. NdisSend (
  2380. &NdisStatus,
  2381. Link->Provider->NdisBindingHandle,
  2382. Packet->NdisPacket);
  2383. }
  2384. else {
  2385. NdisStatus = STATUS_INVALID_DEVICE_STATE;
  2386. }
  2387. }
  2388. //
  2389. // Take the ref count down, which may allow others
  2390. // to come through.
  2391. //
  2392. result = ExInterlockedAddUlong(
  2393. &Link->NdisSendsInProgress,
  2394. (ULONG)-1,
  2395. &Link->SpinLock);
  2396. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2397. NbfPrint1 ("NbfNdisSend: NdisSend completed Status: %s.\n",
  2398. NbfGetNdisStatus(NdisStatus));
  2399. }
  2400. switch (NdisStatus) {
  2401. case NDIS_STATUS_PENDING:
  2402. #if DBG
  2403. NbfSendsPended++;
  2404. #endif
  2405. break;
  2406. case NDIS_STATUS_SUCCESS:
  2407. #if DBG
  2408. NbfSendsCompletedInline++;
  2409. NbfSendsCompletedOk++;
  2410. #endif
  2411. NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
  2412. Packet->NdisPacket,
  2413. NDIS_STATUS_SUCCESS);
  2414. break;
  2415. default:
  2416. #if DBG
  2417. NbfSendsCompletedInline++;
  2418. NbfSendsCompletedFail++;
  2419. #endif
  2420. NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
  2421. Packet->NdisPacket,
  2422. NDIS_STATUS_SUCCESS);
  2423. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2424. NbfPrint1 ("NbfNdisSend failed, status not Pending or Complete: %lx.\n",
  2425. NbfGetNdisStatus (NdisStatus));
  2426. }
  2427. break;
  2428. }
  2429. //
  2430. // We have now sent a packet, see if any queued up while we
  2431. // were doing it. If the count was zero after removing ours,
  2432. // then anything else queued is being processed, so we can
  2433. // exit.
  2434. //
  2435. if (result == 1) {
  2436. return;
  2437. }
  2438. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  2439. p = RemoveHeadList(&Link->NdisSendQueue);
  2440. //
  2441. // If the refcount was not zero, then nobody else should
  2442. // have taken packets off since they would have been
  2443. // blocked by us. So, the queue should not be empty.
  2444. //
  2445. ASSERT (p != &Link->NdisSendQueue);
  2446. //
  2447. // Get back the TP_PACKET by using the Frame pointer in the
  2448. // ProtocolReserved field of the NDIS_PACKET.
  2449. //
  2450. TmpNdisPacket = CONTAINING_RECORD (p, NDIS_PACKET, MacReserved[0]);
  2451. Packet = (PTP_PACKET)(((PSEND_PACKET_TAG)(&TmpNdisPacket->ProtocolReserved[0]))->Frame);
  2452. } // while loop
  2453. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  2454. }
  2455. } /* NbfNdisSend */
  2456. VOID
  2457. RestartLinkTraffic(
  2458. PTP_LINK Link
  2459. )
  2460. /*++
  2461. Routine Description:
  2462. This routine continues the activities of the connections on a link.
  2463. NOTE: This function is called with the link spinlock held and
  2464. it returns with it released. THIS FUNCTION MUST BE CALLED AT
  2465. DPC LEVEL.
  2466. Arguments:
  2467. Link - Pointer to a TP_LINK object.
  2468. Return Value:
  2469. none.
  2470. --*/
  2471. {
  2472. PTP_CONNECTION connection;
  2473. PLIST_ENTRY p;
  2474. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2475. NbfPrint1 ("RestartLinkTraffic: Entered for link %lx.\n", Link);
  2476. }
  2477. //
  2478. // Link conditions may have cleared up. Make all connections on this
  2479. // link eligible for more packetization if they are in W_LINK state.
  2480. //
  2481. for (p = Link->ConnectionDatabase.Flink;
  2482. p != &Link->ConnectionDatabase;
  2483. p = p->Flink) {
  2484. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  2485. ASSERT (connection->LinkSpinLock == &Link->SpinLock);
  2486. //
  2487. // If we tried to send a plain-ole data frame DFM/DOL, but
  2488. // link conditions were not satisfactory, then we changed
  2489. // send state to W_LINK. Check for that now, and possibly
  2490. // start repacketizing.
  2491. //
  2492. if (connection->SendState == CONNECTION_SENDSTATE_W_LINK) {
  2493. if (!(IsListEmpty (&connection->SendQueue))) {
  2494. connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
  2495. //
  2496. // This is similar to calling StartPacketizingConnection
  2497. // with the Immediate set to FALSE.
  2498. //
  2499. if (!(connection->Flags & CONNECTION_FLAGS_PACKETIZE) &&
  2500. (connection->Flags & CONNECTION_FLAGS_READY)) {
  2501. ASSERT (!(connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
  2502. connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
  2503. NbfReferenceConnection ("Packetize", connection, CREF_PACKETIZE_QUEUE);
  2504. ExInterlockedInsertTailList(
  2505. &connection->Provider->PacketizeQueue,
  2506. &connection->PacketizeLinkage,
  2507. &connection->Provider->SpinLock);
  2508. }
  2509. } else {
  2510. connection->SendState = CONNECTION_SENDSTATE_IDLE;
  2511. }
  2512. }
  2513. }
  2514. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  2515. } /* RestartLinkTraffic */
  2516. VOID
  2517. NbfProcessWanDelayedQueue(
  2518. IN PVOID Parameter
  2519. )
  2520. /*++
  2521. Routine Description:
  2522. This is the thread routine which restarts packetizing
  2523. that has been delayed on WAN to allow RRs to come in.
  2524. This is very similar to PacketizeConnections.
  2525. Arguments:
  2526. Parameter - A pointer to the device context.
  2527. Return Value:
  2528. None.
  2529. --*/
  2530. {
  2531. PDEVICE_CONTEXT DeviceContext;
  2532. PLIST_ENTRY p;
  2533. PTP_CONNECTION Connection;
  2534. KIRQL oldirql;
  2535. DeviceContext = (PDEVICE_CONTEXT)Parameter;
  2536. //
  2537. // Packetize all waiting connections
  2538. //
  2539. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  2540. ASSERT (DeviceContext->WanThreadQueued);
  2541. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2542. while (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
  2543. p = RemoveHeadList(&DeviceContext->PacketizeQueue);
  2544. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2545. Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
  2546. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2547. if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
  2548. Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
  2549. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2550. NbfDereferenceConnection ("No longer packetizing", Connection, CREF_PACKETIZE_QUEUE);
  2551. } else {
  2552. NbfReferenceSendIrp ("Packetize", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
  2553. PacketizeSend (Connection, FALSE); // releases the lock.
  2554. }
  2555. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2556. }
  2557. DeviceContext->WanThreadQueued = FALSE;
  2558. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2559. KeLowerIrql (oldirql);
  2560. } /* NbfProcessWanDelayedQueue */
  2561. NTSTATUS
  2562. BuildBufferChainFromMdlChain (
  2563. IN PDEVICE_CONTEXT DeviceContext,
  2564. IN PMDL CurrentMdl,
  2565. IN ULONG ByteOffset,
  2566. IN ULONG DesiredLength,
  2567. OUT PNDIS_BUFFER *Destination,
  2568. OUT PMDL *NewCurrentMdl,
  2569. OUT ULONG *NewByteOffset,
  2570. OUT ULONG *TrueLength
  2571. )
  2572. /*++
  2573. Routine Description:
  2574. This routine is called to build an NDIS_BUFFER chain from a source Mdl chain and
  2575. offset into it. We assume we don't know the length of the source Mdl chain,
  2576. and we must allocate the NDIS_BUFFERs for the destination chain, which
  2577. we do from the NDIS buffer pool.
  2578. The NDIS_BUFFERs that are returned are mapped and locked. (Actually, the pages in
  2579. them are in the same state as those in the source MDLs.)
  2580. If the system runs out of memory while we are building the destination
  2581. NDIS_BUFFER chain, we completely clean up the built chain and return with
  2582. NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
  2583. and ByteOffset. TrueLength is set to 0.
  2584. Environment:
  2585. Kernel Mode, Source Mdls locked. It is recommended, although not required,
  2586. that the source Mdls be mapped and locked prior to calling this routine.
  2587. Arguments:
  2588. BufferPoolHandle - The buffer pool to allocate buffers from.
  2589. CurrentMdl - Points to the start of the Mdl chain from which to draw the
  2590. packet.
  2591. ByteOffset - Offset within this MDL to start the packet at.
  2592. DesiredLength - The number of bytes to insert into the packet.
  2593. Destination - returned pointer to the NDIS_BUFFER chain describing the packet.
  2594. NewCurrentMdl - returned pointer to the Mdl that would be used for the next
  2595. byte of packet. NULL if the source Mdl chain was exhausted.
  2596. NewByteOffset - returned offset into the NewCurrentMdl for the next byte of
  2597. packet. NULL if the source Mdl chain was exhausted.
  2598. TrueLength - The actual length of the returned NDIS_BUFFER Chain. If less than
  2599. DesiredLength, the source Mdl chain was exhausted.
  2600. Return Value:
  2601. STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded (even if
  2602. shorter than the desired chain).
  2603. STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while building the
  2604. destination chain.
  2605. --*/
  2606. {
  2607. ULONG AvailableBytes;
  2608. PMDL OldMdl;
  2609. PNDIS_BUFFER NewNdisBuffer;
  2610. NDIS_STATUS NdisStatus;
  2611. //
  2612. IF_NBFDBG (NBF_DEBUG_NDIS) {
  2613. NbfPrint3 ("BuildBufferChain: Mdl: %lx Offset: %ld Length: %ld\n",
  2614. CurrentMdl, ByteOffset, DesiredLength);
  2615. }
  2616. AvailableBytes = MmGetMdlByteCount (CurrentMdl) - ByteOffset;
  2617. if (AvailableBytes > DesiredLength) {
  2618. AvailableBytes = DesiredLength;
  2619. }
  2620. OldMdl = CurrentMdl;
  2621. *NewCurrentMdl = OldMdl;
  2622. *NewByteOffset = ByteOffset + AvailableBytes;
  2623. *TrueLength = AvailableBytes;
  2624. //
  2625. // Build the first NDIS_BUFFER, which could conceivably be the only one...
  2626. //
  2627. NdisCopyBuffer(
  2628. &NdisStatus,
  2629. &NewNdisBuffer,
  2630. DeviceContext->NdisBufferPool,
  2631. OldMdl,
  2632. ByteOffset,
  2633. AvailableBytes);
  2634. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  2635. *NewByteOffset = ByteOffset;
  2636. *TrueLength = 0;
  2637. *Destination = NULL;
  2638. return STATUS_INSUFFICIENT_RESOURCES;
  2639. }
  2640. *Destination = NewNdisBuffer;
  2641. // IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2642. // PVOID PAddr, UINT PLen;
  2643. // NdisQueryBuffer (NewNdisBuffer, &PAddr, &PLen);
  2644. // NbfPrint4 ("BuildBufferChain: (start)Built Mdl: %lx Length: %lx, Next: %lx Va: %lx\n",
  2645. // NewNdisBuffer, PLen, NDIS_BUFFER_LINKAGE(NewNdisBuffer), PAddr);
  2646. // }
  2647. //
  2648. // Was the first NDIS_BUFFER enough data, or are we out of Mdls?
  2649. //
  2650. if ((AvailableBytes == DesiredLength) || (OldMdl->Next == NULL)) {
  2651. if (*NewByteOffset >= MmGetMdlByteCount (OldMdl)) {
  2652. *NewCurrentMdl = OldMdl->Next;
  2653. *NewByteOffset = 0;
  2654. }
  2655. return STATUS_SUCCESS;
  2656. }
  2657. //
  2658. // Need more data, so follow the in Mdl chain to create a packet.
  2659. //
  2660. OldMdl = OldMdl->Next;
  2661. *NewCurrentMdl = OldMdl;
  2662. while (OldMdl != NULL) {
  2663. AvailableBytes = DesiredLength - *TrueLength;
  2664. if (AvailableBytes > MmGetMdlByteCount (OldMdl)) {
  2665. AvailableBytes = MmGetMdlByteCount (OldMdl);
  2666. }
  2667. NdisCopyBuffer(
  2668. &NdisStatus,
  2669. &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
  2670. DeviceContext->NdisBufferPool,
  2671. OldMdl,
  2672. 0,
  2673. AvailableBytes);
  2674. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  2675. //
  2676. // ran out of resources. put back what we've used in this call and
  2677. // return the error.
  2678. //
  2679. while (*Destination != NULL) {
  2680. NewNdisBuffer = NDIS_BUFFER_LINKAGE(*Destination);
  2681. NdisFreeBuffer (*Destination);
  2682. *Destination = NewNdisBuffer;
  2683. }
  2684. *NewByteOffset = ByteOffset;
  2685. *TrueLength = 0;
  2686. *NewCurrentMdl = CurrentMdl;
  2687. return STATUS_INSUFFICIENT_RESOURCES;
  2688. }
  2689. NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
  2690. *TrueLength += AvailableBytes;
  2691. *NewByteOffset = AvailableBytes;
  2692. // IF_NBFDBG (NBF_DEBUG_SENDENG) {
  2693. // PVOID PAddr, UINT PLen;
  2694. // NdisQueryBuffer (NewNdisBuffer, &PAddr, &PLen);
  2695. // NbfPrint4 ("BuildBufferChain: (continue) Built Mdl: %lx Length: %lx, Next: %lx Va: %lx\n",
  2696. // NewNdisBuffer, PLen, NDIS_BUFFER_LINKAGE(NewNdisBuffer), PAddr);
  2697. // }
  2698. if (*TrueLength == DesiredLength) {
  2699. if (*NewByteOffset == MmGetMdlByteCount (OldMdl)) {
  2700. *NewCurrentMdl = OldMdl->Next;
  2701. *NewByteOffset = 0;
  2702. }
  2703. return STATUS_SUCCESS;
  2704. }
  2705. OldMdl = OldMdl->Next;
  2706. *NewCurrentMdl = OldMdl;
  2707. } // while (mdl chain exists)
  2708. *NewCurrentMdl = NULL;
  2709. *NewByteOffset = 0;
  2710. return STATUS_SUCCESS;
  2711. } // BuildBufferChainFromMdlChain