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.

2888 lines
86 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. send.c
  5. Abstract:
  6. This module contains the send routines for the Netbios
  7. module of the ISN transport.
  8. Author:
  9. Adam Barr (adamba) 22-November-1993
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. //
  17. // Work Item structure for work items put on the Kernel Excutive worker threads
  18. //
  19. typedef struct
  20. {
  21. WORK_QUEUE_ITEM Item; // Used by OS to queue these requests
  22. PVOID Context;
  23. } NBI_WORK_ITEM_CONTEXT;
  24. VOID
  25. SendDgram(
  26. PNDIS_PACKET Packet
  27. )
  28. /*++
  29. Routine Description:
  30. This routine sends a datagram from a Worker thread.
  31. Earlier, this code was part of the NbiSendComplete module,
  32. but since we could end up with a stack overflow, this may
  33. now be handled over a worker thread.
  34. Arguments:
  35. WorkItem - The work item that was allocated for this.
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  41. NDIS_STATUS Status;
  42. PNETBIOS_CACHE CacheName;
  43. PDEVICE Device = NbiDevice;
  44. NB_CONNECTIONLESS UNALIGNED * Header;
  45. PIPX_LOCAL_TARGET LocalTarget;
  46. ULONG HeaderLength;
  47. ULONG PacketLength;
  48. // send the datagram on the next net.
  49. CTEAssert (!Reserved->u.SR_DG.Cache->Unique);
  50. Reserved->SendInProgress = TRUE;
  51. CacheName = Reserved->u.SR_DG.Cache;
  52. //
  53. // Fill in the IPX header -- the default header has the broadcast
  54. // address on net 0 as the destination IPX address, so we modify
  55. // that for the current netbios cache entry if needed.
  56. //
  57. Header = (NB_CONNECTIONLESS UNALIGNED *) (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  58. RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
  59. *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
  60. RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
  61. LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
  62. HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
  63. PacketLength = HeaderLength + (ULONG) REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
  64. Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
  65. Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
  66. Header->IpxHeader.PacketType = 0x04;
  67. //
  68. // Now fill in the Netbios header.
  69. //
  70. Header->Datagram.ConnectionControlFlag = 0x00;
  71. RtlCopyMemory(
  72. Header->Datagram.SourceName,
  73. Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
  74. 16);
  75. if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
  76. //
  77. // This is a directed, as opposed to broadcast, datagram.
  78. //
  79. Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
  80. RtlCopyMemory(
  81. Header->Datagram.DestinationName,
  82. Reserved->u.SR_DG.RemoteName->NetbiosName,
  83. 16);
  84. } else {
  85. Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
  86. RtlZeroMemory(
  87. Header->Datagram.DestinationName,
  88. 16);
  89. }
  90. //
  91. // Now send the frame (IPX will adjust the length of the
  92. // first buffer and the whole frame correctly).
  93. //
  94. if ((Status = (*Device->Bind.SendHandler) (LocalTarget,
  95. Packet,
  96. PacketLength,
  97. HeaderLength)) != STATUS_PENDING) {
  98. NbiSendComplete (Packet, Status);
  99. }
  100. }
  101. VOID
  102. NbiDelayedSendDatagram(
  103. IN PVOID pContextInfo
  104. )
  105. {
  106. NBI_WORK_ITEM_CONTEXT *pContext = (NBI_WORK_ITEM_CONTEXT *) pContextInfo;
  107. PNDIS_PACKET Packet = (PNDIS_PACKET) pContext->Context;
  108. PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  109. Reserved->CurrentSendIteration = 0;
  110. SendDgram (Packet);
  111. NbiFreeMemory (pContextInfo, sizeof(NBI_WORK_ITEM_CONTEXT), MEMORY_WORK_ITEM,
  112. "Free delayed DgramSend work item");
  113. }
  114. VOID
  115. NbiSendComplete(
  116. IN PNDIS_PACKET Packet,
  117. IN NDIS_STATUS Status
  118. )
  119. /*++
  120. Routine Description:
  121. This routine handles a send completion call from IPX.
  122. Arguments:
  123. Packet - The packet which has been completed.
  124. Status - The status of the send.
  125. Return Value:
  126. None.
  127. --*/
  128. {
  129. PDEVICE Device = NbiDevice;
  130. PADDRESS Address;
  131. PADDRESS_FILE AddressFile;
  132. PCONNECTION Connection;
  133. PREQUEST DatagramRequest;
  134. PREQUEST SendRequest, TmpRequest;
  135. PNDIS_BUFFER CurBuffer, TmpBuffer;
  136. PNETBIOS_CACHE CacheName;
  137. PNDIS_BUFFER SecondBuffer = NULL;
  138. PVOID SecondBufferMemory = NULL;
  139. UINT SecondBufferLength;
  140. ULONG oldvalue;
  141. PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  142. CTELockHandle CancelLH;
  143. #if defined(_PNP_POWER)
  144. CTELockHandle LockHandle;
  145. #endif _PNP_POWER
  146. //
  147. // We jump back here if we re-call send from inside this
  148. // function and it doesn't pend (to avoid stack overflow).
  149. //
  150. ++Device->Statistics.PacketsSent;
  151. switch (Reserved->Type) {
  152. case SEND_TYPE_SESSION_DATA:
  153. //
  154. // This was a send on a session. This references the
  155. // IRP.
  156. //
  157. NB_DEBUG2 (SEND, ("Complete NDIS packet %lx\n", Reserved));
  158. CTEAssert (Reserved->SendInProgress);
  159. Reserved->SendInProgress = FALSE;
  160. Connection = Reserved->u.SR_CO.Connection;
  161. SendRequest = Reserved->u.SR_CO.Request;
  162. if (!Reserved->u.SR_CO.NoNdisBuffer) {
  163. CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
  164. while (CurBuffer) {
  165. TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
  166. NdisFreeBuffer (CurBuffer);
  167. CurBuffer = TmpBuffer;
  168. }
  169. }
  170. //
  171. // If NoNdisBuffer is TRUE, then we could set
  172. // Connection->SendBufferInUse to FALSE here. The
  173. // problem is that a new send might be in progress
  174. // by the time this completes and it may have
  175. // used the user buffer, then if we need to
  176. // retransmit that packet we would use the buffer
  177. // twice. We instead rely on the fact that whenever
  178. // we make a new send active we set SendBufferInUse
  179. // to FALSE. The net effect is that the user's buffer
  180. // can be used the first time a send is packetize
  181. // but not on resends.
  182. //
  183. NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
  184. NdisRecalculatePacketCounts (Packet);
  185. #if DBG
  186. if (REQUEST_REFCOUNT(SendRequest) > 100) {
  187. DbgPrint ("Request %lx (%lx) has high refcount\n",
  188. Connection, SendRequest);
  189. DbgBreakPoint();
  190. }
  191. #endif
  192. #if defined(__PNP)
  193. NB_GET_LOCK( &Connection->Lock, &LockHandle );
  194. oldvalue = REQUEST_REFCOUNT(SendRequest)--;
  195. if ( DEVICE_NETWORK_PATH_NOT_FOUND == Status ) {
  196. Connection->LocalTarget = Reserved->LocalTarget;
  197. }
  198. NB_FREE_LOCK( &Connection->Lock, LockHandle );
  199. #else
  200. oldvalue = NB_ADD_ULONG(
  201. &REQUEST_REFCOUNT (SendRequest),
  202. (ULONG)-1,
  203. &Connection->Lock);
  204. #endif __PNP
  205. if (oldvalue == 1) {
  206. //
  207. // If the refcount on this request is now zero then
  208. // we already got the ack for it, which means
  209. // that the ack-processing code has unlinked the
  210. // request from Connection->SendQueue. So we
  211. // can just run the queue of connections here
  212. // and complete them.
  213. //
  214. // We dereference the connection for all but one
  215. // of the requests, we hang on to that until a bit
  216. // later so everything stays around.
  217. //
  218. while (TRUE) {
  219. TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
  220. NB_DEBUG2 (SEND, ("Completing request %lx from send complete\n", SendRequest));
  221. REQUEST_STATUS (SendRequest) = STATUS_SUCCESS;
  222. NB_GET_CANCEL_LOCK( &CancelLH );
  223. IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
  224. NB_FREE_CANCEL_LOCK( CancelLH );
  225. NbiCompleteRequest (SendRequest);
  226. NbiFreeRequest (Device, SendRequest);
  227. ++Connection->ConnectionInfo.TransmittedTsdus;
  228. SendRequest = TmpRequest;
  229. if (SendRequest == NULL) {
  230. break;
  231. }
  232. NbiDereferenceConnection (Connection, CREF_SEND);
  233. }
  234. }
  235. if (Reserved->OwnedByConnection) {
  236. Connection->SendPacketInUse = FALSE;
  237. if (Connection->OnWaitPacketQueue) {
  238. //
  239. // This will put the connection on the packetize
  240. // queue if appropriate.
  241. //
  242. NbiCheckForWaitPacket (Connection);
  243. }
  244. } else {
  245. NbiPushSendPacket(Reserved);
  246. }
  247. if (oldvalue == 1) {
  248. NbiDereferenceConnection (Connection, CREF_SEND);
  249. }
  250. break;
  251. case SEND_TYPE_NAME_FRAME:
  252. //
  253. // The frame is an add name/delete name; put it back in
  254. // the pool and deref the address.
  255. //
  256. CTEAssert (Reserved->SendInProgress);
  257. Address = Reserved->u.SR_NF.Address;
  258. Reserved->SendInProgress = FALSE;
  259. NbiPushSendPacket (Reserved);
  260. if (Address) {
  261. NbiDereferenceAddress (Address, AREF_NAME_FRAME);
  262. } else {
  263. NbiDereferenceDevice (Device, DREF_NAME_FRAME);
  264. }
  265. break;
  266. case SEND_TYPE_SESSION_INIT:
  267. //
  268. // This is a session initialize or session init ack; free
  269. // the second buffer, put the packet back in the pool and
  270. // deref the device.
  271. //
  272. CTEAssert (Reserved->SendInProgress);
  273. Reserved->SendInProgress = FALSE;
  274. NdisUnchainBufferAtBack (Packet, &SecondBuffer);
  275. if (SecondBuffer)
  276. {
  277. NdisQueryBufferSafe (SecondBuffer, &SecondBufferMemory, &SecondBufferLength, HighPagePriority);
  278. CTEAssert (SecondBufferLength == sizeof(NB_SESSION_INIT));
  279. if (SecondBufferMemory)
  280. {
  281. NbiFreeMemory (SecondBufferMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION,
  282. "Session Initialize");
  283. }
  284. NdisFreeBuffer(SecondBuffer);
  285. }
  286. NbiPushSendPacket (Reserved);
  287. NbiDereferenceDevice (Device, DREF_SESSION_INIT);
  288. break;
  289. case SEND_TYPE_SESSION_NO_DATA:
  290. //
  291. // This is a frame which was sent on a connection but
  292. // has no data (ack, session end, session end ack).
  293. //
  294. CTEAssert (Reserved->SendInProgress);
  295. Reserved->SendInProgress = FALSE;
  296. Connection = Reserved->u.SR_CO.Connection;
  297. if (Reserved->OwnedByConnection) {
  298. CTEAssert (Connection != NULL);
  299. Connection->SendPacketInUse = FALSE;
  300. if (Connection->OnWaitPacketQueue) {
  301. //
  302. // This will put the connection on the packetize
  303. // queue if appropriate.
  304. //
  305. NbiCheckForWaitPacket (Connection);
  306. }
  307. } else {
  308. NbiPushSendPacket(Reserved);
  309. }
  310. if (Connection != NULL) {
  311. NbiDereferenceConnection (Connection, CREF_FRAME);
  312. } else {
  313. NbiDereferenceDevice (Device, DREF_FRAME);
  314. }
  315. break;
  316. case SEND_TYPE_FIND_NAME:
  317. //
  318. // The frame is a find name; just set SendInProgress to
  319. // FALSE and FindNameTimeout will clean it up.
  320. //
  321. #if defined(_PNP_POWER)
  322. NB_GET_LOCK( &Device->Lock, &LockHandle);
  323. CTEAssert (Reserved->SendInProgress);
  324. Reserved->SendInProgress = FALSE;
  325. //
  326. // We keep track of when it finds a net that isn't
  327. // a down wan line so that we can tell when datagram
  328. // sends should fail (otherwise we succeed them, so
  329. // the browser won't think this is a down wan line).
  330. //
  331. if ( STATUS_SUCCESS == Status ) {
  332. NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
  333. } else {
  334. NB_DEBUG( CACHE, ("Send complete of find name with failure %lx\n",Status ));
  335. }
  336. NB_FREE_LOCK(&Device->Lock, LockHandle);
  337. #else
  338. CTEAssert (Reserved->SendInProgress);
  339. Reserved->SendInProgress = FALSE;
  340. #endif _PNP_POWER
  341. break;
  342. case SEND_TYPE_DATAGRAM:
  343. //
  344. // If there are any more networks to send this on then
  345. // do so, otherwise put it back in the pool and complete
  346. // the request.
  347. //
  348. CTEAssert (Reserved->SendInProgress);
  349. Reserved->SendInProgress = FALSE;
  350. if ((Reserved->u.SR_DG.Cache == NULL) ||
  351. (++Reserved->u.SR_DG.CurrentNetwork >=
  352. Reserved->u.SR_DG.Cache->NetworksUsed)) {
  353. AddressFile = Reserved->u.SR_DG.AddressFile;
  354. DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
  355. NB_DEBUG2 (DATAGRAM, ("Completing datagram %lx on %lx\n", DatagramRequest, AddressFile));
  356. //
  357. // Remove any user buffers chained on this packet.
  358. //
  359. NdisReinitializePacket (Packet);
  360. NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
  361. NdisChainBufferAtFront (Packet, Reserved->HeaderBuffer);
  362. //
  363. // Complete the request.
  364. //
  365. REQUEST_STATUS(DatagramRequest) = Status;
  366. NbiCompleteRequest(DatagramRequest);
  367. NbiFreeRequest (Device, DatagramRequest);
  368. CacheName = Reserved->u.SR_DG.Cache;
  369. NbiPushSendPacket (Reserved);
  370. //
  371. // Since we are no longer referencing the cache
  372. // name, see if we should delete it (this will
  373. // happen if the cache entry was aged out while
  374. // the datagram was being processed).
  375. //
  376. if (CacheName != NULL) {
  377. oldvalue = NB_ADD_ULONG(
  378. &CacheName->ReferenceCount,
  379. (ULONG)-1,
  380. &Device->Lock);
  381. if (oldvalue == 1) {
  382. NB_DEBUG2 (CACHE, ("Free aged cache entry %lx\n", CacheName));
  383. NbiFreeMemory(
  384. CacheName,
  385. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  386. MEMORY_CACHE,
  387. "Free old cache");
  388. }
  389. }
  390. NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
  391. } else {
  392. NBI_WORK_ITEM_CONTEXT *WorkItem;
  393. if ((++Reserved->CurrentSendIteration >= MAX_SEND_ITERATIONS) &&
  394. (WorkItem = (NBI_WORK_ITEM_CONTEXT *) NbiAllocateMemory (sizeof(NBI_WORK_ITEM_CONTEXT),
  395. MEMORY_WORK_ITEM,
  396. "Delayed DgramSend work item")))
  397. {
  398. WorkItem->Context = (PVOID) Packet;
  399. ExInitializeWorkItem (&WorkItem->Item, NbiDelayedSendDatagram, (PVOID)WorkItem);
  400. ExQueueWorkItem(&WorkItem->Item, DelayedWorkQueue);
  401. }
  402. else
  403. {
  404. SendDgram (Packet);
  405. }
  406. }
  407. break;
  408. case SEND_TYPE_STATUS_QUERY:
  409. //
  410. // This is an adapter status query, which is a simple
  411. // packet.
  412. //
  413. CTEAssert (Reserved->SendInProgress);
  414. Reserved->SendInProgress = FALSE;
  415. NbiPushSendPacket (Reserved);
  416. NbiDereferenceDevice (Device, DREF_STATUS_FRAME);
  417. break;
  418. case SEND_TYPE_STATUS_RESPONSE:
  419. //
  420. // This is an adapter status response, we have to free the
  421. // second buffer.
  422. //
  423. CTEAssert (Reserved->SendInProgress);
  424. Reserved->SendInProgress = FALSE;
  425. NdisUnchainBufferAtBack (Packet, &SecondBuffer);
  426. if (SecondBuffer)
  427. {
  428. NdisQueryBufferSafe (SecondBuffer, &SecondBufferMemory, &SecondBufferLength, HighPagePriority);
  429. if (SecondBufferMemory)
  430. {
  431. NbiFreeMemory (SecondBufferMemory, Reserved->u.SR_AS.ActualBufferLength, MEMORY_STATUS,
  432. "Adapter Status");
  433. }
  434. NdisFreeBuffer(SecondBuffer);
  435. }
  436. NbiPushSendPacket (Reserved);
  437. NbiDereferenceDevice (Device, DREF_STATUS_RESPONSE);
  438. break;
  439. #ifdef RSRC_TIMEOUT_DBG
  440. case SEND_TYPE_DEATH_PACKET:
  441. //
  442. // This is a session initialize or session init ack; free
  443. // the second buffer, put the packet back in the pool and
  444. // deref the device.
  445. //
  446. CTEAssert (Reserved->SendInProgress);
  447. Reserved->SendInProgress = FALSE;
  448. DbgPrint("********Death packet send completed status %lx\n",Status);
  449. DbgBreakPoint();
  450. break;
  451. #endif //RSRC_TIMEOUT_DBG
  452. default:
  453. CTEAssert (FALSE);
  454. break;
  455. }
  456. } /* NbiSendComplete */
  457. #if 0
  458. ULONG NbiLoudSendQueue = 1;
  459. #endif
  460. VOID
  461. NbiAssignSequenceAndSend(
  462. IN PCONNECTION Connection,
  463. IN PNDIS_PACKET Packet
  464. IN NB_LOCK_HANDLE_PARAM(LockHandle)
  465. )
  466. /*++
  467. Routine Description:
  468. This routine is used to ensure that receive sequence numbers on
  469. packets are numbered correctly. It is called in place of the lower-level
  470. send handler; after assigning the receive sequence number it locks out
  471. other sends until the NdisSend call has returned (not necessarily completed),
  472. insuring that the packets with increasing receive sequence numbers
  473. are queue in the right order by the MAC.
  474. NOTE: THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD, AND
  475. RETURNS WITH IT RELEASED.
  476. Arguments:
  477. Connection - The connection the send is on.
  478. Packet - The packet to send.
  479. LockHandle - The handle with which Connection->Lock was acquired.
  480. Return Value:
  481. None.
  482. --*/
  483. {
  484. NDIS_STATUS NdisStatus;
  485. PNB_SEND_RESERVED Reserved;
  486. PLIST_ENTRY p;
  487. NB_CONNECTION UNALIGNED * Header;
  488. PDEVICE Device = NbiDevice;
  489. BOOLEAN NdisSendReference;
  490. ULONG result;
  491. Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  492. CTEAssert (Connection->State == CONNECTION_STATE_ACTIVE);
  493. //
  494. // If there is a send in progress, then queue this packet
  495. // and return.
  496. //
  497. if (Connection->NdisSendsInProgress > 0) {
  498. NB_DEBUG2 (SEND, ("Queueing send packet %lx on %lx\n", Reserved, Connection));
  499. InsertTailList (&Connection->NdisSendQueue, &Reserved->WaitLinkage);
  500. ++Connection->NdisSendsInProgress;
  501. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  502. return;
  503. }
  504. //
  505. // No send in progress. Set the flag to true, and fill in the
  506. // receive sequence fields in the packet.
  507. //
  508. Connection->NdisSendsInProgress = 1;
  509. NdisSendReference = FALSE;
  510. Connection->NdisSendReference = &NdisSendReference;
  511. while (TRUE) {
  512. Header = (NB_CONNECTION UNALIGNED *)
  513. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  514. Header->Session.ReceiveSequence = Connection->ReceiveSequence;
  515. if (Connection->NewNetbios) {
  516. Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
  517. } else {
  518. Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
  519. }
  520. //
  521. // Since we are acking as much as we know, we can clear
  522. // this flag. The connection will eventually get removed
  523. // from the queue by the long timeout.
  524. //
  525. Connection->DataAckPending = FALSE;
  526. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  527. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
  528. NdisStatus = (*Device->Bind.SendHandler)(
  529. &Connection->LocalTarget,
  530. Packet,
  531. Reserved->u.SR_CO.PacketLength,
  532. sizeof(NB_CONNECTION));
  533. if (NdisStatus != NDIS_STATUS_PENDING) {
  534. NbiSendComplete(
  535. Packet,
  536. NdisStatus);
  537. }
  538. //
  539. // Take the ref count down, which may allow others
  540. // to come through.
  541. //
  542. result = NB_ADD_ULONG(
  543. &Connection->NdisSendsInProgress,
  544. (ULONG)-1,
  545. &Connection->Lock);
  546. //
  547. // We have now sent a packet, see if any queued up while we
  548. // were doing it. If the count was zero after removing ours,
  549. // then anything else queued is being processed, so we can
  550. // exit. If the connection was stopped while we were sending,
  551. // a special reference was added which we remove (NbiStopConnection
  552. // sets NdisSendReference to TRUE, using the pointer saved
  553. // in Connection->NdisSendReference).
  554. //
  555. if (result == 1) {
  556. if (NdisSendReference) {
  557. NB_DEBUG2 (SEND, ("Remove CREF_NDIS_SEND from %lx\n", Connection));
  558. NbiDereferenceConnection (Connection, CREF_NDIS_SEND);
  559. }
  560. return;
  561. }
  562. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  563. p = RemoveHeadList(&Connection->NdisSendQueue);
  564. //
  565. // If the refcount was not zero, then nobody else should
  566. // have taken packets off since they would have been
  567. // blocked by us. So, the queue should not be empty.
  568. //
  569. ASSERT (p != &Connection->NdisSendQueue);
  570. Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
  571. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  572. } // while loop
  573. //
  574. // We should never reach here.
  575. //
  576. CTEAssert (FALSE);
  577. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  578. } /* NbiAssignSequenceAndSend */
  579. NTSTATUS
  580. NbiTdiSend(
  581. IN PDEVICE Device,
  582. IN PREQUEST Request
  583. )
  584. /*++
  585. Routine Description:
  586. This routine does a send on an active connection.
  587. Arguments:
  588. Device - The netbios device.
  589. Request - The request describing the send.
  590. Return Value:
  591. NTSTATUS - status of operation.
  592. --*/
  593. {
  594. PCONNECTION Connection;
  595. PTDI_REQUEST_KERNEL_SEND Parameters;
  596. NB_DEFINE_SYNC_CONTEXT (SyncContext)
  597. NB_DEFINE_LOCK_HANDLE (LockHandle)
  598. CTELockHandle CancelLH;
  599. //
  600. // Check that the file type is valid
  601. //
  602. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  603. {
  604. CTEAssert(FALSE);
  605. return (STATUS_INVALID_ADDRESS_COMPONENT);
  606. }
  607. //
  608. // First make sure the connection is valid.
  609. //
  610. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  611. if (Connection->Type == NB_CONNECTION_SIGNATURE) {
  612. NB_GET_CANCEL_LOCK( &CancelLH );
  613. NB_BEGIN_SYNC (&SyncContext);
  614. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  615. //
  616. // Make sure the connection is in a good state.
  617. //
  618. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  619. //
  620. // If the connection is idle then send it now, otherwise
  621. // queue it.
  622. //
  623. if (!Request->Cancel) {
  624. Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
  625. //
  626. // For old netbios, don't allow sends greater than 64K-1.
  627. //
  628. if ((Connection->NewNetbios) ||
  629. (Parameters->SendLength <= 0xffff)) {
  630. IoSetCancelRoutine (Request, NbiCancelSend);
  631. NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
  632. NB_FREE_CANCEL_LOCK( CancelLH );
  633. REQUEST_INFORMATION (Request) = Parameters->SendLength; // assume it succeeds.
  634. REQUEST_REFCOUNT (Request) = 1; // refcount starts at 1.
  635. NbiReferenceConnectionSync (Connection, CREF_SEND);
  636. //
  637. // NOTE: The connection send queue is managed such
  638. // that the current send being packetized is not on
  639. // the queue. For multiple-request messages, the
  640. // first one is not on the queue, but its linkage
  641. // field points to the next request in the message
  642. // (which will be on the head of the queue).
  643. //
  644. if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
  645. //
  646. // This is a final send.
  647. //
  648. if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
  649. NB_DEBUG2 (SEND, ("Send %lx, connection %lx idle\n", Request, Connection));
  650. Connection->CurrentSend.Request = Request;
  651. Connection->CurrentSend.MessageOffset = 0;
  652. Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
  653. Connection->CurrentSend.BufferOffset = 0;
  654. Connection->SendBufferInUse = FALSE;
  655. Connection->UnAckedSend = Connection->CurrentSend;
  656. Connection->FirstMessageRequest = Request;
  657. #ifdef RSRC_TIMEOUT_DBG
  658. KeQuerySystemTime(&Connection->FirstMessageRequestTime);
  659. (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
  660. Connection->FirstMessageRequestTime.QuadPart;
  661. #endif //RSRC_TIMEOUT_DBG
  662. Connection->LastMessageRequest = Request;
  663. Connection->CurrentMessageLength = Parameters->SendLength;
  664. //
  665. // This frees the connection lock.
  666. //
  667. NbiPacketizeSend(
  668. Connection
  669. NB_LOCK_HANDLE_ARG(LockHandle)
  670. );
  671. } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
  672. //
  673. // We have been collecting partial sends waiting
  674. // for a final one, which we have now received,
  675. // so start packetizing.
  676. //
  677. // We chain it on the back of the send queue,
  678. // in addition if this is the second request in the
  679. // message, we have to link the first request (which
  680. // is not on the queue) to this one.
  681. //
  682. //
  683. NB_DEBUG2 (SEND, ("Send %lx, connection %lx got eor\n", Request, Connection));
  684. Connection->LastMessageRequest = Request;
  685. Connection->CurrentMessageLength += Parameters->SendLength;
  686. if (Connection->SendQueue.Head == NULL) {
  687. REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
  688. }
  689. REQUEST_SINGLE_LINKAGE(Request) = NULL;
  690. REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
  691. Connection->UnAckedSend = Connection->CurrentSend;
  692. #ifdef RSRC_TIMEOUT_DBG
  693. {
  694. LARGE_INTEGER Time;
  695. KeQuerySystemTime(&Time);
  696. (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
  697. Time.QuadPart;
  698. }
  699. #endif //RSRC_TIMEOUT_DBG
  700. //
  701. // This frees the connection lock.
  702. //
  703. NbiPacketizeSend(
  704. Connection
  705. NB_LOCK_HANDLE_ARG(LockHandle)
  706. );
  707. } else {
  708. //
  709. // The state is PACKETIZE, W_ACK, or W_PACKET.
  710. //
  711. NB_DEBUG2 (SEND, ("Send %lx, connection %lx busy\n", Request, Connection));
  712. REQUEST_SINGLE_LINKAGE(Request) = NULL;
  713. REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
  714. #ifdef RSRC_TIMEOUT_DBG
  715. {
  716. LARGE_INTEGER Time;
  717. KeQuerySystemTime(&Time);
  718. (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
  719. Time.QuadPart;
  720. }
  721. #endif //RSRC_TIMEOUT_DBG
  722. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  723. }
  724. } else {
  725. //
  726. // This is a partial send. We queue them up without
  727. // packetizing until we get a final (this is because
  728. // we have to put a correct Connection->CurrentMessageLength
  729. // in the frames.
  730. //
  731. if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
  732. //
  733. // Start collecting partial sends. NOTE: Partial sends
  734. // are always inserted in the send queue
  735. //
  736. Connection->CurrentSend.Request = Request;
  737. Connection->CurrentSend.MessageOffset = 0;
  738. Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
  739. Connection->CurrentSend.BufferOffset = 0;
  740. Connection->SendBufferInUse = FALSE;
  741. Connection->FirstMessageRequest = Request;
  742. #ifdef RSRC_TIMEOUT_DBG
  743. KeQuerySystemTime(&Connection->FirstMessageRequestTime);
  744. (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
  745. Connection->FirstMessageRequestTime.QuadPart;
  746. #endif //RSRC_TIMEOUT_DBG
  747. Connection->CurrentMessageLength = Parameters->SendLength;
  748. Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
  749. } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
  750. //
  751. // We have got another partial send to add to our
  752. // list. We chain it on the back of the send queue,
  753. // in addition if this is the second request in the
  754. // message, we have to link the first request (which
  755. // is not on the queue) to this one.
  756. //
  757. Connection->LastMessageRequest = Request;
  758. Connection->CurrentMessageLength += Parameters->SendLength;
  759. if (Connection->SendQueue.Head == NULL) {
  760. REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
  761. }
  762. REQUEST_SINGLE_LINKAGE(Request) = NULL;
  763. REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
  764. #ifdef RSRC_TIMEOUT_DBG
  765. {
  766. LARGE_INTEGER Time;
  767. KeQuerySystemTime(&Time);
  768. (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
  769. Time.QuadPart;
  770. }
  771. #endif //RSRC_TIMEOUT_DBG
  772. } else {
  773. REQUEST_SINGLE_LINKAGE(Request) = NULL;
  774. REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
  775. #ifdef RSRC_TIMEOUT_DBG
  776. {
  777. LARGE_INTEGER Time;
  778. KeQuerySystemTime(&Time);
  779. (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
  780. Time.QuadPart;
  781. }
  782. #endif //RSRC_TIMEOUT_DBG
  783. }
  784. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  785. }
  786. NB_END_SYNC (&SyncContext);
  787. return STATUS_PENDING;
  788. } else {
  789. NB_DEBUG2 (SEND, ("Send %lx, too long for connection %lx (%d)\n", Request, Connection, Parameters->SendLength));
  790. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  791. NB_END_SYNC (&SyncContext);
  792. NB_FREE_CANCEL_LOCK( CancelLH );
  793. return STATUS_INVALID_PARAMETER;
  794. }
  795. } else {
  796. NB_DEBUG2 (SEND, ("Send %lx, connection %lx cancelled\n", Request, Connection));
  797. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  798. NB_END_SYNC (&SyncContext);
  799. NB_FREE_CANCEL_LOCK( CancelLH );
  800. return STATUS_CANCELLED;
  801. }
  802. } else {
  803. NB_DEBUG (SEND, ("Send connection %lx state is %d\n", Connection, Connection->State));
  804. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  805. NB_END_SYNC (&SyncContext);
  806. NB_FREE_CANCEL_LOCK( CancelLH );
  807. return STATUS_INVALID_CONNECTION;
  808. }
  809. } else {
  810. NB_DEBUG (SEND, ("Send connection %lx has bad signature\n", Connection));
  811. return STATUS_INVALID_CONNECTION;
  812. }
  813. } /* NbiTdiSend */
  814. VOID
  815. NbiPacketizeSend(
  816. IN PCONNECTION Connection
  817. IN NB_LOCK_HANDLE_PARAM(LockHandle)
  818. )
  819. /*++
  820. Routine Description:
  821. This routine does a send on an active connection.
  822. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  823. AND RETURNS WITH IT RELEASED.
  824. Arguments:
  825. Connection - The connection.
  826. LockHandle - The handle used to acquire the lock.
  827. Return Value:
  828. None.
  829. --*/
  830. {
  831. PREQUEST Request;
  832. PNDIS_PACKET Packet;
  833. PNDIS_BUFFER BufferChain;
  834. PNB_SEND_RESERVED Reserved;
  835. PDEVICE Device = NbiDevice;
  836. NB_CONNECTION UNALIGNED * Header;
  837. ULONG PacketLength;
  838. ULONG PacketSize;
  839. ULONG DesiredLength;
  840. ULONG ActualLength;
  841. NTSTATUS Status;
  842. PSINGLE_LIST_ENTRY s;
  843. USHORT ThisSendSequence;
  844. USHORT ThisOffset;
  845. BOOLEAN ExitAfterSend;
  846. UCHAR ConnectionControlFlag;
  847. CTELockHandle DeviceLockHandle;
  848. //
  849. // We jump back here if we are talking new Netbios and it
  850. // is OK to packetize another send.
  851. //
  852. SendAnotherPacket:
  853. //
  854. // If we decide to packetize another send after this, we
  855. // change ExitAfterSend to FALSE and SubState to PACKETIZE.
  856. // Right now we don't change SubState in case it is W_PACKET.
  857. //
  858. ExitAfterSend = TRUE;
  859. CTEAssert (Connection->CurrentSend.Request != NULL);
  860. if (Connection->NewNetbios) {
  861. //
  862. // Check that we have send window, both that advertised
  863. // by the remote and our own locally-decided window which
  864. // may be smaller.
  865. //
  866. if (((USHORT)(Connection->CurrentSend.SendSequence-1) == Connection->RemoteRcvSequenceMax) ||
  867. (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize)) {
  868. //
  869. // Keep track of whether we are waiting because of his window
  870. // or because of our local window. If it is because of our local
  871. // window then we may want to adjust it after this window
  872. // is acked.
  873. //
  874. if ((USHORT)(Connection->CurrentSend.SendSequence-1) != Connection->RemoteRcvSequenceMax) {
  875. Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
  876. NB_DEBUG2 (SEND, ("Connection %lx local shut down at %lx, %lx\n", Connection, Connection->CurrentSend.SendSequence, Connection->UnAckedSend.SendSequence));
  877. } else {
  878. Connection->SubState = CONNECTION_SUBSTATE_A_REMOTE_W;
  879. NB_DEBUG2 (SEND, ("Connection %lx remote shut down at %lx\n", Connection, Connection->CurrentSend.SendSequence));
  880. }
  881. //
  882. // Start the timer so we will keep bugging him about
  883. // this. What if he doesn't get a receive down
  884. // quickly -- but this is better than losing his ack
  885. // and then dying. We won't really back off our timer
  886. // because we will keep getting acks, and resetting it.
  887. //
  888. NbiStartRetransmit (Connection);
  889. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  890. return;
  891. }
  892. }
  893. Request = Connection->CurrentSend.Request;
  894. //
  895. // If we are in this routine then we know that
  896. // we are coming out of IDLE, W_ACK, or W_PACKET
  897. // and we still have the lock held. We also know
  898. // that there is a send request in progress. If
  899. // an ack for none or part of the last packet was
  900. // received, then our send pointers have been
  901. // adjusted to reflect that.
  902. //
  903. //
  904. // First get a packet for the current send.
  905. //
  906. if (!Connection->SendPacketInUse) {
  907. Connection->SendPacketInUse = TRUE;
  908. Packet = PACKET(&Connection->SendPacket);
  909. Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  910. } else {
  911. s = ExInterlockedPopEntrySList(
  912. &Device->SendPacketList,
  913. &NbiGlobalPoolInterlock);
  914. if (s == NULL) {
  915. //
  916. // This function tries to allocate another packet pool.
  917. //
  918. s = NbiPopSendPacket(Device, FALSE);
  919. if (s == NULL) {
  920. //
  921. // It is possible to come in here and already be in
  922. // W_PACKET state -- this is because we may packetize
  923. // when in that state, and rather than always be
  924. // checking that we weren't in W_PACKET, we go
  925. // ahead and check again here.
  926. //
  927. if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PACKET) {
  928. Connection->SubState = CONNECTION_SUBSTATE_A_W_PACKET;
  929. NB_GET_LOCK (&Device->Lock, &DeviceLockHandle);
  930. if (!Connection->OnWaitPacketQueue) {
  931. NbiReferenceConnectionLock (Connection, CREF_W_PACKET);
  932. Connection->OnWaitPacketQueue = TRUE;
  933. InsertTailList(
  934. &Device->WaitPacketConnections,
  935. &Connection->WaitPacketLinkage
  936. );
  937. // NB_INSERT_TAIL_LIST(
  938. // &Device->WaitPacketConnections,
  939. // &Connection->WaitPacketLinkage,
  940. // &Device->Lock);
  941. }
  942. NB_FREE_LOCK (&Device->Lock, DeviceLockHandle);
  943. }
  944. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  945. return;
  946. }
  947. }
  948. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  949. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  950. }
  951. //
  952. // Set this now, we will change it later if needed.
  953. //
  954. Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
  955. //
  956. // Save these since they go in this next packet.
  957. //
  958. ThisSendSequence = Connection->CurrentSend.SendSequence;
  959. ThisOffset = (USHORT)Connection->CurrentSend.MessageOffset;
  960. //
  961. // Now see if we need to copy the buffer chain.
  962. //
  963. PacketSize = Connection->MaximumPacketSize;
  964. if (Connection->CurrentSend.MessageOffset + PacketSize >= Connection->CurrentMessageLength) {
  965. PacketSize = Connection->CurrentMessageLength - Connection->CurrentSend.MessageOffset;
  966. if ((Connection->CurrentSend.MessageOffset == 0) &&
  967. (!Connection->SendBufferInUse)) {
  968. //
  969. // If the entire send remaining fits in one packet,
  970. // and this is also the first packet in the send,
  971. // then the entire send fits in one packet and
  972. // we don't need to build a duplicate buffer chain.
  973. //
  974. BufferChain = Connection->CurrentSend.Buffer;
  975. Reserved->u.SR_CO.NoNdisBuffer = TRUE;
  976. Connection->CurrentSend.Buffer = NULL;
  977. Connection->CurrentSend.BufferOffset = 0;
  978. Connection->CurrentSend.MessageOffset = Connection->CurrentMessageLength;
  979. Connection->CurrentSend.Request = NULL;
  980. ++Connection->CurrentSend.SendSequence;
  981. Connection->SendBufferInUse = TRUE;
  982. if (Connection->NewNetbios) {
  983. if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
  984. ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
  985. TDI_SEND_NO_RESPONSE_EXPECTED)) { // optimize this check
  986. ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
  987. } else {
  988. ConnectionControlFlag = NB_CONTROL_EOM;
  989. }
  990. Connection->PiggybackAckTimeout = FALSE;
  991. } else {
  992. ConnectionControlFlag = NB_CONTROL_SEND_ACK;
  993. }
  994. if (BufferChain != NULL) {
  995. NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), user buffer\n",
  996. Reserved, Connection,
  997. Connection->CurrentSend.SendSequence,
  998. Connection->CurrentSend.MessageOffset));
  999. NdisChainBufferAtBack (Packet, BufferChain);
  1000. } else {
  1001. NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no buffer\n",
  1002. Reserved, Connection,
  1003. Connection->CurrentSend.SendSequence,
  1004. Connection->CurrentSend.MessageOffset));
  1005. }
  1006. goto GotBufferChain;
  1007. }
  1008. }
  1009. //
  1010. // We need to build a partial buffer chain. In the case
  1011. // where the current request is a partial one, we may
  1012. // build this from the ndis buffer chains of several
  1013. // requests.
  1014. //
  1015. if (PacketSize > 0) {
  1016. DesiredLength = PacketSize;
  1017. NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), allocate buffer\n",
  1018. Reserved, Connection,
  1019. Connection->CurrentSend.SendSequence,
  1020. Connection->CurrentSend.MessageOffset));
  1021. while (TRUE) {
  1022. Status = NbiBuildBufferChainFromBufferChain (
  1023. Device->NdisBufferPoolHandle,
  1024. Connection->CurrentSend.Buffer,
  1025. Connection->CurrentSend.BufferOffset,
  1026. DesiredLength,
  1027. &BufferChain,
  1028. &Connection->CurrentSend.Buffer,
  1029. &Connection->CurrentSend.BufferOffset,
  1030. &ActualLength);
  1031. if (Status != STATUS_SUCCESS) {
  1032. PNDIS_BUFFER CurBuffer, TmpBuffer;
  1033. NB_DEBUG2 (SEND, ("Allocate buffer chain failed for packet %lx\n", Reserved));
  1034. //
  1035. // We could not allocate resources for this send.
  1036. // We'll put the connection on the packetize
  1037. // queue and hope we get more resources later.
  1038. //
  1039. NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
  1040. CTEAssert (!Connection->OnPacketizeQueue);
  1041. Connection->OnPacketizeQueue = TRUE;
  1042. //
  1043. // Connection->CurrentSend can stay where it is.
  1044. //
  1045. NB_INSERT_TAIL_LIST(
  1046. &Device->PacketizeConnections,
  1047. &Connection->PacketizeLinkage,
  1048. &Device->Lock);
  1049. Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
  1050. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1051. //
  1052. // Free any buffers we have allocated on previous calls
  1053. // to BuildBufferChain inside this same while(TRUE) loop,
  1054. // then free the packet.
  1055. //
  1056. CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
  1057. while (CurBuffer) {
  1058. TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
  1059. NdisFreeBuffer (CurBuffer);
  1060. CurBuffer = TmpBuffer;
  1061. }
  1062. NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
  1063. NdisRecalculatePacketCounts (Packet);
  1064. if (Reserved->OwnedByConnection) {
  1065. Connection->SendPacketInUse = FALSE;
  1066. } else {
  1067. NbiPushSendPacket(Reserved);
  1068. }
  1069. return;
  1070. }
  1071. NdisChainBufferAtBack (Packet, BufferChain);
  1072. Connection->CurrentSend.MessageOffset += ActualLength;
  1073. DesiredLength -= ActualLength;
  1074. if (DesiredLength == 0) {
  1075. //
  1076. // We have gotten enough data for our packet.
  1077. //
  1078. if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
  1079. Connection->CurrentSend.Request = NULL;
  1080. }
  1081. break;
  1082. }
  1083. //
  1084. // We ran out of buffer chain on this send, which means
  1085. // that we must have another one behind it (since we
  1086. // don't start packetizing partial sends until all of
  1087. // them are queued).
  1088. //
  1089. Request = REQUEST_SINGLE_LINKAGE(Request);
  1090. if (Request == NULL) {
  1091. KeBugCheck (NDIS_INTERNAL_ERROR);
  1092. }
  1093. Connection->CurrentSend.Request = Request;
  1094. Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
  1095. Connection->CurrentSend.BufferOffset = 0;
  1096. }
  1097. } else {
  1098. //
  1099. // This is a zero-length send (in general we will go
  1100. // through the code before the if that uses the user's
  1101. // buffer, but not on a resend).
  1102. //
  1103. Connection->CurrentSend.Buffer = NULL;
  1104. Connection->CurrentSend.BufferOffset = 0;
  1105. CTEAssert (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength);
  1106. Connection->CurrentSend.Request = NULL;
  1107. NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no alloc buf\n",
  1108. Reserved, Connection,
  1109. Connection->CurrentSend.SendSequence,
  1110. Connection->CurrentSend.MessageOffset));
  1111. }
  1112. Reserved->u.SR_CO.NoNdisBuffer = FALSE;
  1113. if (Connection->NewNetbios) {
  1114. ++Connection->CurrentSend.SendSequence;
  1115. if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
  1116. if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
  1117. ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
  1118. } else if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
  1119. ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
  1120. TDI_SEND_NO_RESPONSE_EXPECTED)) { // optimize this check
  1121. ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
  1122. } else {
  1123. ConnectionControlFlag = NB_CONTROL_EOM;
  1124. }
  1125. Connection->PiggybackAckTimeout = FALSE;
  1126. } else if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
  1127. ConnectionControlFlag = NB_CONTROL_SEND_ACK;
  1128. } else if (ThisSendSequence == Connection->RemoteRcvSequenceMax) {
  1129. ConnectionControlFlag = NB_CONTROL_SEND_ACK;
  1130. } else {
  1131. ConnectionControlFlag = 0;
  1132. ExitAfterSend = FALSE;
  1133. Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
  1134. }
  1135. } else {
  1136. ConnectionControlFlag = NB_CONTROL_SEND_ACK;
  1137. if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
  1138. ++Connection->CurrentSend.SendSequence;
  1139. }
  1140. }
  1141. GotBufferChain:
  1142. //
  1143. // We have a packet and a buffer chain, there are
  1144. // no other resources required for a send so we can
  1145. // fill in the header and go.
  1146. //
  1147. CTEAssert (Reserved->SendInProgress == FALSE);
  1148. Reserved->SendInProgress = TRUE;
  1149. Reserved->Type = SEND_TYPE_SESSION_DATA;
  1150. Reserved->u.SR_CO.Connection = Connection;
  1151. Reserved->u.SR_CO.Request = Connection->FirstMessageRequest;
  1152. PacketLength = PacketSize + sizeof(NB_CONNECTION);
  1153. Reserved->u.SR_CO.PacketLength = PacketLength;
  1154. Header = (NB_CONNECTION UNALIGNED *)
  1155. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  1156. RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
  1157. Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
  1158. Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
  1159. Header->IpxHeader.PacketType = 0x04;
  1160. //
  1161. // Now fill in the Netbios header. Put this in
  1162. // a contiguous buffer in the connection ?
  1163. //
  1164. Header->Session.ConnectionControlFlag = ConnectionControlFlag;
  1165. Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
  1166. Header->Session.SourceConnectionId = Connection->LocalConnectionId;
  1167. Header->Session.DestConnectionId = Connection->RemoteConnectionId;
  1168. Header->Session.SendSequence = ThisSendSequence;
  1169. Header->Session.TotalDataLength = (USHORT)Connection->CurrentMessageLength;
  1170. Header->Session.Offset = ThisOffset;
  1171. Header->Session.DataLength = (USHORT)PacketSize;
  1172. #if 0
  1173. //
  1174. // These are set by NbiAssignSequenceAndSend.
  1175. //
  1176. Header->Session.ReceiveSequence = Connection->ReceiveSequence;
  1177. Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
  1178. #endif
  1179. //
  1180. // Reference the request to account for this send.
  1181. //
  1182. #if DBG
  1183. if (REQUEST_REFCOUNT(Request) > 100) {
  1184. DbgPrint ("Request %lx (%lx) has high refcount\n",
  1185. Connection, Request);
  1186. DbgBreakPoint();
  1187. }
  1188. #endif
  1189. ++REQUEST_REFCOUNT (Request);
  1190. ++Device->TempFramesSent;
  1191. Device->TempFrameBytesSent += PacketSize;
  1192. //
  1193. // Start the timer.
  1194. //
  1195. NbiStartRetransmit (Connection);
  1196. //
  1197. // This frees the lock. IPX will adjust the length of
  1198. // the first buffer correctly.
  1199. //
  1200. NbiAssignSequenceAndSend(
  1201. Connection,
  1202. Packet
  1203. NB_LOCK_HANDLE_ARG(LockHandle));
  1204. if (!ExitAfterSend) {
  1205. //
  1206. // Did we need to reference the connection until we
  1207. // get the lock back??
  1208. //
  1209. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  1210. if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
  1211. (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
  1212. //
  1213. // Jump back to the beginning of the function to
  1214. // repacketize.
  1215. goto SendAnotherPacket;
  1216. } else {
  1217. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1218. }
  1219. }
  1220. } /* NbiPacketizeSend */
  1221. VOID
  1222. NbiAdjustSendWindow(
  1223. IN PCONNECTION Connection
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. This routine adjusts a connection's send window if needed. It is
  1228. assumed that we just got an ack for a full send window.
  1229. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  1230. AND RETURNS WITH IT HELD.
  1231. Arguments:
  1232. Connection - The connection.
  1233. Return Value:
  1234. None.
  1235. --*/
  1236. {
  1237. if (Connection->RetransmitThisWindow) {
  1238. //
  1239. // Move it down. Check if this keeps happening.
  1240. //
  1241. if (Connection->SendWindowSize > 2) {
  1242. --Connection->SendWindowSize;
  1243. NB_DEBUG2 (SEND_WINDOW, ("Lower window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
  1244. }
  1245. if (Connection->SendWindowIncrease) {
  1246. //
  1247. // We just increased the window.
  1248. //
  1249. ++Connection->IncreaseWindowFailures;
  1250. NB_DEBUG2 (SEND_WINDOW, ("%d consecutive increase failues on %lx (%lx)\n", Connection->IncreaseWindowFailures, Connection, Connection->CurrentSend.SendSequence));
  1251. if (Connection->IncreaseWindowFailures >= 2) {
  1252. if (Connection->MaxSendWindowSize > 2) {
  1253. //
  1254. // Lock ourselves at a smaller window.
  1255. //
  1256. Connection->MaxSendWindowSize = Connection->SendWindowSize;
  1257. NB_DEBUG2 (SEND_WINDOW, ("Lock send window at %d on %lx (%lx)\n", Connection->MaxSendWindowSize, Connection, Connection->CurrentSend.SendSequence));
  1258. }
  1259. Connection->IncreaseWindowFailures = 0;
  1260. }
  1261. Connection->SendWindowIncrease = FALSE;
  1262. }
  1263. } else {
  1264. //
  1265. // Increase it if allowed, and make a note
  1266. // in case this increase causes problems in
  1267. // the next window.
  1268. //
  1269. if (Connection->SendWindowSize < Connection->MaxSendWindowSize) {
  1270. ++Connection->SendWindowSize;
  1271. NB_DEBUG2 (SEND_WINDOW, ("Raise window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
  1272. Connection->SendWindowIncrease = TRUE;
  1273. } else {
  1274. if (Connection->SendWindowIncrease) {
  1275. //
  1276. // We just increased it and nothing failed,
  1277. // which is good.
  1278. //
  1279. Connection->SendWindowIncrease = FALSE;
  1280. Connection->IncreaseWindowFailures = 0;
  1281. NB_DEBUG2 (SEND_WINDOW, ("Raised window OK on %lx (%lx)\n", Connection, Connection->CurrentSend.SendSequence));
  1282. }
  1283. }
  1284. }
  1285. //
  1286. // This controls when we'll check this again.
  1287. //
  1288. Connection->SendWindowSequenceLimit += Connection->SendWindowSize;
  1289. } /* NbiAdjustSendWindow */
  1290. VOID
  1291. NbiReframeConnection(
  1292. IN PCONNECTION Connection,
  1293. IN USHORT ReceiveSequence,
  1294. IN USHORT BytesReceived,
  1295. IN BOOLEAN Resend
  1296. IN NB_LOCK_HANDLE_PARAM(LockHandle)
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine is called when we have gotten an ack
  1301. for some data. It completes any sends that have
  1302. been acked, and if needed modifies the current send
  1303. pointer and queues the connection for repacketizing.
  1304. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  1305. AND RETURNS WITH IT RELEASED.
  1306. Arguments:
  1307. Connection - The connection.
  1308. ReceiveSequence - The receive sequence from the remote.
  1309. BytesReceived - The number of bytes received in this message.
  1310. Resend - If it is OK to resend based on this packet.
  1311. LockHandle - The handle with which Connection->Lock was acquired.
  1312. Return Value:
  1313. None.
  1314. --*/
  1315. {
  1316. PREQUEST Request, TmpRequest;
  1317. PREQUEST RequestToComplete;
  1318. PDEVICE Device = NbiDevice;
  1319. CTELockHandle CancelLH;
  1320. //
  1321. // We should change to stop the timer
  1322. // only if we go idle, since otherwise we still
  1323. // want it running, or will restart it when we
  1324. // packetize.
  1325. //
  1326. //
  1327. // See how much is acked here.
  1328. //
  1329. if ((Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) &&
  1330. (ReceiveSequence == (USHORT)(Connection->CurrentSend.SendSequence)) &&
  1331. (Connection->FirstMessageRequest != NULL)) {
  1332. // Special check for 0 length send which was not accepted by the remote.
  1333. // In this case it will pass the above 3 conditions yet, nothing
  1334. // is acked. BUG#10395
  1335. if (!Connection->CurrentSend.MessageOffset && Connection->CurrentSend.SendSequence == Connection->UnAckedSend.SendSequence ) {
  1336. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1337. return;
  1338. }
  1339. //
  1340. // This acks the entire message.
  1341. //
  1342. NB_DEBUG2 (SEND, ("Got ack for entire message on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
  1343. NbiStopRetransmit (Connection);
  1344. Connection->CurrentSend.MessageOffset = 0; // Needed?
  1345. Connection->UnAckedSend.MessageOffset = 0;
  1346. //
  1347. // We don't adjust the send window since we likely stopped
  1348. // packetizing before we hit it.
  1349. //
  1350. Connection->Retries = NbiDevice->KeepAliveCount;
  1351. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1352. if (Connection->NewNetbios) {
  1353. Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
  1354. //
  1355. // See if we need to adjust our send window.
  1356. //
  1357. if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
  1358. NbiAdjustSendWindow (Connection);
  1359. } else {
  1360. //
  1361. // Advance this, we won't get meaningful results until we
  1362. // send a full window in one message.
  1363. //
  1364. Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
  1365. }
  1366. }
  1367. Connection->RetransmitThisWindow = FALSE;
  1368. Request = Connection->FirstMessageRequest;
  1369. //
  1370. // We dequeue these requests from the connection's
  1371. // send queue.
  1372. //
  1373. if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
  1374. REQUEST_SINGLE_LINKAGE (Request) = NULL;
  1375. } else {
  1376. Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
  1377. REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
  1378. }
  1379. #if DBG
  1380. if (REQUEST_REFCOUNT(Request) > 100) {
  1381. DbgPrint ("Request %lx (%lx) has high refcount\n",
  1382. Connection, Request);
  1383. DbgBreakPoint();
  1384. }
  1385. #endif
  1386. if (--REQUEST_REFCOUNT(Request) == 0) {
  1387. RequestToComplete = Request;
  1388. } else {
  1389. //
  1390. // There are still sends pending, this will get
  1391. // completed when the last send completes. Since
  1392. // we have already unlinked the request from the
  1393. // connection's send queue we can do this without
  1394. // any locks.
  1395. //
  1396. RequestToComplete = NULL;
  1397. }
  1398. //
  1399. // Now see if there is a send to activate.
  1400. //
  1401. NbiRestartConnection (Connection);
  1402. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1403. //
  1404. // Now complete any requests we need to.
  1405. //
  1406. while (RequestToComplete != NULL) {
  1407. TmpRequest = REQUEST_SINGLE_LINKAGE (RequestToComplete);
  1408. REQUEST_STATUS (RequestToComplete) = STATUS_SUCCESS;
  1409. NB_GET_CANCEL_LOCK( &CancelLH );
  1410. IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
  1411. NB_FREE_CANCEL_LOCK( CancelLH );
  1412. NbiCompleteRequest (RequestToComplete);
  1413. NbiFreeRequest (Device, RequestToComplete);
  1414. ++Connection->ConnectionInfo.TransmittedTsdus;
  1415. RequestToComplete = TmpRequest;
  1416. NbiDereferenceConnection (Connection, CREF_SEND);
  1417. }
  1418. } else if ((ReceiveSequence == Connection->CurrentSend.SendSequence) &&
  1419. (Connection->NewNetbios || (BytesReceived == Connection->CurrentSend.MessageOffset)) &&
  1420. (Connection->CurrentSend.Request != NULL)) {
  1421. //
  1422. // This acks whatever we sent last time, and we are
  1423. // not done packetizing this send, so we can repacketize.
  1424. // With SendSequence changing as it does now,
  1425. // don't need the CurrentSend.Request check???
  1426. //
  1427. NB_DEBUG2 (SEND, ("Got full ack on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
  1428. NbiStopRetransmit (Connection);
  1429. if (Connection->NewNetbios) {
  1430. //
  1431. // If we are waiting for a window, and this does not open it
  1432. // anymore, then we don't reset our timers/retries.
  1433. //
  1434. if (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) {
  1435. if (Connection->RemoteRcvSequenceMax != BytesReceived) {
  1436. Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
  1437. Connection->Retries = NbiDevice->KeepAliveCount;
  1438. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1439. }
  1440. //
  1441. // Advance this, we won't get meaningful results until we
  1442. // send a full window in one message.
  1443. //
  1444. Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
  1445. } else {
  1446. Connection->Retries = NbiDevice->KeepAliveCount;
  1447. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1448. Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
  1449. if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
  1450. NbiAdjustSendWindow (Connection);
  1451. } else {
  1452. //
  1453. // Advance this, we won't get meaningful results until we
  1454. // send a full window in one message.
  1455. //
  1456. Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
  1457. }
  1458. }
  1459. } else {
  1460. Connection->Retries = NbiDevice->KeepAliveCount;
  1461. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1462. }
  1463. Connection->RetransmitThisWindow = FALSE;
  1464. Connection->UnAckedSend = Connection->CurrentSend;
  1465. if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
  1466. //
  1467. // We may be on if this ack is duplicated.
  1468. //
  1469. NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
  1470. CTEAssert(!Connection->OnPacketizeQueue);
  1471. Connection->OnPacketizeQueue = TRUE;
  1472. NB_INSERT_TAIL_LIST(
  1473. &Device->PacketizeConnections,
  1474. &Connection->PacketizeLinkage,
  1475. &Device->Lock);
  1476. Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
  1477. }
  1478. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1479. } else if( Connection->FirstMessageRequest ) {
  1480. //
  1481. // This acked part of the current send. If the
  1482. // remote is requesting a resend then we advance
  1483. // the current send location by the amount
  1484. // acked and resend from there. If he does
  1485. // not want a resend, just ignore this.
  1486. //
  1487. // We repacketize immediately because we have
  1488. // backed up the pointer, and this would
  1489. // cause us to ignore an ack for the amount
  1490. // sent. Since we don't release the lock
  1491. // until we have packetized, the current
  1492. // pointer will be advanced past there.
  1493. //
  1494. // If he is acking more than we sent, we
  1495. // ignore this -- the remote is confused and there
  1496. // is nothing much we can do.
  1497. //
  1498. if (Resend) {
  1499. if (Connection->NewNetbios &&
  1500. (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
  1501. (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
  1502. (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
  1503. ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
  1504. ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
  1505. (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
  1506. BOOLEAN SomethingAcked = (BOOLEAN)
  1507. (ReceiveSequence != Connection->UnAckedSend.SendSequence);
  1508. //
  1509. // New netbios and the receive sequence is valid.
  1510. //
  1511. NbiStopRetransmit (Connection);
  1512. //
  1513. // Advance our unacked pointer by the amount
  1514. // acked in this response.
  1515. //
  1516. NbiAdvanceUnAckedBySequence(
  1517. Connection,
  1518. ReceiveSequence);
  1519. Connection->RetransmitThisWindow = TRUE;
  1520. ++Connection->ConnectionInfo.TransmissionErrors;
  1521. ++Device->Statistics.DataFramesResent;
  1522. ADD_TO_LARGE_INTEGER(
  1523. &Device->Statistics.DataFrameBytesResent,
  1524. Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
  1525. //
  1526. // Packetize from that point on.
  1527. //
  1528. Connection->CurrentSend = Connection->UnAckedSend;
  1529. //
  1530. // If anything was acked, then reset the retry count.
  1531. //
  1532. if (SomethingAcked) {
  1533. //
  1534. // See if we need to adjust our send window.
  1535. //
  1536. if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
  1537. NbiAdjustSendWindow (Connection);
  1538. }
  1539. Connection->Retries = NbiDevice->KeepAliveCount;
  1540. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1541. }
  1542. Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
  1543. //
  1544. // Now packetize. This will set the state to
  1545. // something meaningful and release the lock.
  1546. //
  1547. if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
  1548. NbiPacketizeSend(
  1549. Connection
  1550. NB_LOCK_HANDLE_ARG(LockHandle)
  1551. );
  1552. } else {
  1553. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1554. }
  1555. } else if (!Connection->NewNetbios &&
  1556. ((ReceiveSequence == Connection->UnAckedSend.SendSequence) &&
  1557. (BytesReceived <= Connection->CurrentSend.MessageOffset))) {
  1558. ULONG BytesAcked =
  1559. BytesReceived - Connection->UnAckedSend.MessageOffset;
  1560. //
  1561. // Old netbios.
  1562. //
  1563. NbiStopRetransmit (Connection);
  1564. //
  1565. // Advance our unacked pointer by the amount
  1566. // acked in this response.
  1567. //
  1568. NbiAdvanceUnAckedByBytes(
  1569. Connection,
  1570. BytesAcked);
  1571. ++Connection->ConnectionInfo.TransmissionErrors;
  1572. ++Device->Statistics.DataFramesResent;
  1573. ADD_TO_LARGE_INTEGER(
  1574. &Device->Statistics.DataFrameBytesResent,
  1575. Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
  1576. //
  1577. // Packetize from that point on.
  1578. //
  1579. Connection->CurrentSend = Connection->UnAckedSend;
  1580. //
  1581. // If anything was acked, reset the retry count
  1582. //
  1583. if ( BytesAcked ) {
  1584. Connection->Retries = NbiDevice->KeepAliveCount;
  1585. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1586. }
  1587. //
  1588. // Now packetize. This will set the state to
  1589. // something meaningful and release the lock.
  1590. //
  1591. if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
  1592. NbiPacketizeSend(
  1593. Connection
  1594. NB_LOCK_HANDLE_ARG(LockHandle)
  1595. );
  1596. } else {
  1597. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1598. }
  1599. } else {
  1600. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1601. }
  1602. } else {
  1603. if (Connection->NewNetbios &&
  1604. (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
  1605. (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
  1606. (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
  1607. ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
  1608. ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
  1609. (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
  1610. BOOLEAN SomethingAcked = (BOOLEAN)
  1611. (ReceiveSequence != Connection->UnAckedSend.SendSequence);
  1612. //
  1613. // New netbios and the receive sequence is valid. We advance
  1614. // the back of our send window, but we don't repacketize.
  1615. //
  1616. //
  1617. // Advance our unacked pointer by the amount
  1618. // acked in this response.
  1619. //
  1620. NbiAdvanceUnAckedBySequence(
  1621. Connection,
  1622. ReceiveSequence);
  1623. Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
  1624. //
  1625. // If anything was acked, then reset the retry count.
  1626. //
  1627. if (SomethingAcked) {
  1628. //
  1629. // See if we need to adjust our send window.
  1630. //
  1631. if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
  1632. NbiAdjustSendWindow (Connection);
  1633. }
  1634. Connection->Retries = NbiDevice->KeepAliveCount;
  1635. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  1636. //
  1637. // Now packetize. This will set the state to
  1638. // something meaningful and release the lock.
  1639. //
  1640. if ((Connection->CurrentSend.Request != NULL) &&
  1641. (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE)) {
  1642. NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
  1643. CTEAssert(!Connection->OnPacketizeQueue);
  1644. Connection->OnPacketizeQueue = TRUE;
  1645. Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
  1646. NB_INSERT_TAIL_LIST(
  1647. &Device->PacketizeConnections,
  1648. &Connection->PacketizeLinkage,
  1649. &Device->Lock);
  1650. }
  1651. }
  1652. }
  1653. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1654. }
  1655. } else {
  1656. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1657. }
  1658. } /* NbiReframeConnection */
  1659. VOID
  1660. NbiRestartConnection(
  1661. IN PCONNECTION Connection
  1662. )
  1663. /*++
  1664. Routine Description:
  1665. This routine is called when have gotten an ack for
  1666. a full message, or received a response to a watchdog
  1667. probe, and need to check if the connection should
  1668. start packetizing.
  1669. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  1670. AND RETURNS WITH IT HELD.
  1671. Arguments:
  1672. Connection - The connection.
  1673. Return Value:
  1674. None.
  1675. --*/
  1676. {
  1677. PREQUEST Request, TmpRequest;
  1678. ULONG TempCount;
  1679. PTDI_REQUEST_KERNEL_SEND Parameters;
  1680. PDEVICE Device = NbiDevice;
  1681. //
  1682. // See if there is a send to activate.
  1683. //
  1684. if (Connection->SendQueue.Head != NULL) {
  1685. //
  1686. // Take the first send off the queue and make
  1687. // it current.
  1688. //
  1689. Request = Connection->SendQueue.Head;
  1690. Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Request);
  1691. //
  1692. // Cache the information about being EOM
  1693. // in a more easily accessible location?
  1694. //
  1695. Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
  1696. if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
  1697. //
  1698. // This is a one-request message.
  1699. //
  1700. Connection->CurrentSend.Request = Request;
  1701. Connection->CurrentSend.MessageOffset = 0;
  1702. Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
  1703. Connection->CurrentSend.BufferOffset = 0;
  1704. Connection->SendBufferInUse = FALSE;
  1705. Connection->UnAckedSend = Connection->CurrentSend;
  1706. Connection->FirstMessageRequest = Request;
  1707. #ifdef RSRC_TIMEOUT_DBG
  1708. KeQuerySystemTime(&Connection->FirstMessageRequestTime);
  1709. #endif //RSRC_TIMEOUT_DBG
  1710. Connection->LastMessageRequest = Request;
  1711. Connection->CurrentMessageLength = Parameters->SendLength;
  1712. Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
  1713. NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
  1714. CTEAssert (!Connection->OnPacketizeQueue);
  1715. Connection->OnPacketizeQueue = TRUE;
  1716. NB_INSERT_TAIL_LIST(
  1717. &Device->PacketizeConnections,
  1718. &Connection->PacketizeLinkage,
  1719. &Device->Lock);
  1720. } else {
  1721. //
  1722. // This is a multiple-request message. We scan
  1723. // to see if we have the end of message received
  1724. // yet.
  1725. //
  1726. TempCount = Parameters->SendLength;
  1727. TmpRequest = Request;
  1728. Request = REQUEST_SINGLE_LINKAGE(Request);
  1729. while (Request != NULL) {
  1730. TempCount += Parameters->SendLength;
  1731. Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
  1732. if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
  1733. Connection->CurrentSend.Request = TmpRequest;
  1734. Connection->CurrentSend.MessageOffset = 0;
  1735. Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (TmpRequest);
  1736. Connection->CurrentSend.BufferOffset = 0;
  1737. Connection->SendBufferInUse = FALSE;
  1738. Connection->UnAckedSend = Connection->CurrentSend;
  1739. Connection->FirstMessageRequest = TmpRequest;
  1740. Connection->LastMessageRequest = Request;
  1741. #ifdef RSRC_TIMEOUT_DBG
  1742. KeQuerySystemTime(&Connection->FirstMessageRequestTime);
  1743. #endif //RSRC_TIMEOUT_DBG
  1744. Connection->CurrentMessageLength = TempCount;
  1745. Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
  1746. NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
  1747. CTEAssert (!Connection->OnPacketizeQueue);
  1748. Connection->OnPacketizeQueue = TRUE;
  1749. NB_INSERT_TAIL_LIST(
  1750. &Device->PacketizeConnections,
  1751. &Connection->PacketizeLinkage,
  1752. &Device->Lock);
  1753. break;
  1754. }
  1755. Request = REQUEST_SINGLE_LINKAGE(Request);
  1756. }
  1757. if (Request == NULL) {
  1758. Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
  1759. }
  1760. }
  1761. } else {
  1762. Connection->FirstMessageRequest = NULL;
  1763. Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
  1764. NbiStartWatchdog (Connection);
  1765. }
  1766. } /* NbiRestartConnection */
  1767. VOID
  1768. NbiAdvanceUnAckedByBytes(
  1769. IN PCONNECTION Connection,
  1770. IN ULONG BytesAcked
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. This routine advances the Connection->UnAckedSend
  1775. send pointer by the specified number of bytes. It
  1776. assumes that there are enough send requests to
  1777. handle the number specified.
  1778. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  1779. AND RETURNS WITH IT HELD.
  1780. Arguments:
  1781. Connection - The connection.
  1782. BytesAcked - The number of bytes acked.
  1783. Return Value:
  1784. NTSTATUS - status of operation.
  1785. --*/
  1786. {
  1787. ULONG CurSendBufferLength;
  1788. ULONG BytesLeft = BytesAcked;
  1789. ULONG TempBytes;
  1790. while (BytesLeft > 0) {
  1791. NdisQueryBufferSafe (Connection->UnAckedSend.Buffer, NULL, &CurSendBufferLength, HighPagePriority);
  1792. //
  1793. // See if bytes acked ends within the current buffer.
  1794. //
  1795. if (Connection->UnAckedSend.BufferOffset + BytesLeft <
  1796. CurSendBufferLength) {
  1797. Connection->UnAckedSend.BufferOffset += BytesLeft;
  1798. Connection->UnAckedSend.MessageOffset += BytesLeft;
  1799. break;
  1800. } else {
  1801. TempBytes = CurSendBufferLength - Connection->UnAckedSend.BufferOffset;
  1802. BytesLeft -= TempBytes;
  1803. Connection->UnAckedSend.MessageOffset += TempBytes;
  1804. //
  1805. // No, so advance the buffer.
  1806. //
  1807. Connection->UnAckedSend.BufferOffset = 0;
  1808. Connection->UnAckedSend.Buffer =
  1809. NDIS_BUFFER_LINKAGE (Connection->UnAckedSend.Buffer);
  1810. //
  1811. // Is there a next buffer in this request?
  1812. //
  1813. if (Connection->UnAckedSend.Buffer == NULL) {
  1814. //
  1815. // No, so advance the request unless we are done.
  1816. //
  1817. if (BytesLeft == 0) {
  1818. return;
  1819. }
  1820. Connection->UnAckedSend.Request =
  1821. REQUEST_SINGLE_LINKAGE(Connection->UnAckedSend.Request);
  1822. if (Connection->UnAckedSend.Request == NULL) {
  1823. KeBugCheck (NDIS_INTERNAL_ERROR);
  1824. }
  1825. Connection->UnAckedSend.Buffer =
  1826. REQUEST_NDIS_BUFFER (Connection->UnAckedSend.Request);
  1827. }
  1828. }
  1829. }
  1830. } /* NbiAdvanceUnAckedByBytes */
  1831. VOID
  1832. NbiAdvanceUnAckedBySequence(
  1833. IN PCONNECTION Connection,
  1834. IN USHORT ReceiveSequence
  1835. )
  1836. /*++
  1837. Routine Description:
  1838. This routine advances the Connection->UnAckedSend
  1839. send pointer so that the next packet to send will be
  1840. the correct one for ReceiveSequence. UnAckedSend
  1841. must point to a known valid combination. It
  1842. assumes that there are enough send requests to
  1843. handle the sequence specified.
  1844. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  1845. AND RETURNS WITH IT HELD.
  1846. Arguments:
  1847. Connection - The connection.
  1848. Return Value:
  1849. NTSTATUS - status of operation.
  1850. --*/
  1851. {
  1852. USHORT PacketsAcked;
  1853. //
  1854. // Fix this to account for partial sends, where
  1855. // we might not have used the max. for all packets.
  1856. //
  1857. PacketsAcked = ReceiveSequence - Connection->UnAckedSend.SendSequence;
  1858. NbiAdvanceUnAckedByBytes(
  1859. Connection,
  1860. PacketsAcked * Connection->MaximumPacketSize);
  1861. Connection->UnAckedSend.SendSequence += PacketsAcked;
  1862. } /* NbiAdvanceUnAckedBySequence */
  1863. VOID
  1864. NbiCancelSend(
  1865. IN PDEVICE_OBJECT DeviceObject,
  1866. IN PIRP Irp
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. This routine is called by the I/O system to cancel a send
  1871. The request is found on the connection's send queue.
  1872. NOTE: This routine is called with the CancelSpinLock held and
  1873. is responsible for releasing it.
  1874. Arguments:
  1875. DeviceObject - Pointer to the device object for this driver.
  1876. Irp - Pointer to the request packet representing the I/O request.
  1877. Return Value:
  1878. none.
  1879. --*/
  1880. {
  1881. PCONNECTION Connection;
  1882. PREQUEST Request = (PREQUEST)Irp;
  1883. NB_DEFINE_LOCK_HANDLE (LockHandle)
  1884. NB_DEFINE_SYNC_CONTEXT (SyncContext)
  1885. CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1886. (REQUEST_MINOR_FUNCTION(Request) == TDI_SEND));
  1887. CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
  1888. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1889. //
  1890. // Just stop the connection, that will tear down any
  1891. // sends.
  1892. //
  1893. // Do we care about cancelling non-active
  1894. // sends without stopping the connection??
  1895. //
  1896. NbiReferenceConnectionSync (Connection, CREF_CANCEL);
  1897. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1898. NB_BEGIN_SYNC (&SyncContext);
  1899. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  1900. //
  1901. // This frees the lock, cancels any sends, etc.
  1902. //
  1903. NbiStopConnection(
  1904. Connection,
  1905. STATUS_CANCELLED
  1906. NB_LOCK_HANDLE_ARG (LockHandle));
  1907. NbiDereferenceConnection (Connection, CREF_CANCEL);
  1908. NB_END_SYNC (&SyncContext);
  1909. } /* NbiCancelSend */
  1910. NTSTATUS
  1911. NbiBuildBufferChainFromBufferChain (
  1912. IN NDIS_HANDLE BufferPoolHandle,
  1913. IN PNDIS_BUFFER CurrentSourceBuffer,
  1914. IN ULONG CurrentByteOffset,
  1915. IN ULONG DesiredLength,
  1916. OUT PNDIS_BUFFER *DestinationBuffer,
  1917. OUT PNDIS_BUFFER *NewSourceBuffer,
  1918. OUT ULONG *NewByteOffset,
  1919. OUT ULONG *ActualLength
  1920. )
  1921. /*++
  1922. Routine Description:
  1923. This routine is called to build an NDIS_BUFFER chain from a source
  1924. NDIS_BUFFER chain and offset into it. We assume we don't know the
  1925. length of the source Mdl chain, and we must allocate the NDIS_BUFFERs
  1926. for the destination chain, which we do from the NDIS buffer pool.
  1927. If the system runs out of memory while we are building the destination
  1928. NDIS_BUFFER chain, we completely clean up the built chain and return with
  1929. NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
  1930. and ByteOffset.
  1931. Environment:
  1932. Arguments:
  1933. BufferPoolHandle - The buffer pool to allocate buffers from.
  1934. CurrentSourceBuffer - Points to the start of the NDIS_BUFFER chain
  1935. from which to draw the packet.
  1936. CurrentByteOffset - Offset within this NDIS_BUFFER to start the packet at.
  1937. DesiredLength - The number of bytes to insert into the packet.
  1938. DestinationBuffer - returned pointer to the NDIS_BUFFER chain describing
  1939. the packet.
  1940. NewSourceBuffer - returned pointer to the NDIS_BUFFER that would
  1941. be used for the next byte of packet. NULL if the source NDIS_BUFFER
  1942. chain was exhausted.
  1943. NewByteOffset - returned offset into the NewSourceBuffer for the next byte
  1944. of packet. NULL if the source NDIS_BUFFER chain was exhausted.
  1945. ActualLength - The actual length of the data copied.
  1946. Return Value:
  1947. STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded
  1948. and was the correct length.
  1949. STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while
  1950. building the destination chain.
  1951. --*/
  1952. {
  1953. ULONG AvailableBytes;
  1954. ULONG CurrentByteCount;
  1955. ULONG BytesCopied;
  1956. PNDIS_BUFFER OldNdisBuffer;
  1957. PNDIS_BUFFER NewNdisBuffer;
  1958. NDIS_STATUS NdisStatus;
  1959. OldNdisBuffer = CurrentSourceBuffer;
  1960. NdisQueryBufferSafe (OldNdisBuffer, NULL, &CurrentByteCount, HighPagePriority);
  1961. AvailableBytes = CurrentByteCount - CurrentByteOffset;
  1962. if (AvailableBytes > DesiredLength) {
  1963. AvailableBytes = DesiredLength;
  1964. }
  1965. //
  1966. // Build the first NDIS_BUFFER, which could conceivably be the only one...
  1967. //
  1968. NdisCopyBuffer(
  1969. &NdisStatus,
  1970. &NewNdisBuffer,
  1971. BufferPoolHandle,
  1972. OldNdisBuffer,
  1973. CurrentByteOffset,
  1974. AvailableBytes);
  1975. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  1976. *NewSourceBuffer = CurrentSourceBuffer;
  1977. *NewByteOffset = CurrentByteOffset;
  1978. return STATUS_INSUFFICIENT_RESOURCES;
  1979. }
  1980. *DestinationBuffer = NewNdisBuffer;
  1981. BytesCopied = AvailableBytes;
  1982. //
  1983. // Was the first NDIS_BUFFER enough data.
  1984. //
  1985. if (BytesCopied == DesiredLength) {
  1986. if (CurrentByteOffset + AvailableBytes == CurrentByteCount) {
  1987. *NewSourceBuffer = CurrentSourceBuffer->Next;
  1988. *NewByteOffset = 0;
  1989. } else {
  1990. *NewSourceBuffer = CurrentSourceBuffer;
  1991. *NewByteOffset = CurrentByteOffset + AvailableBytes;
  1992. }
  1993. *ActualLength = BytesCopied;
  1994. return STATUS_SUCCESS;
  1995. }
  1996. if (CurrentSourceBuffer->Next == NULL) {
  1997. *NewSourceBuffer = NULL;
  1998. *NewByteOffset = 0;
  1999. *ActualLength = BytesCopied;
  2000. return STATUS_SUCCESS;
  2001. }
  2002. //
  2003. // Need more data, so follow the in Mdl chain to create a packet.
  2004. //
  2005. OldNdisBuffer = OldNdisBuffer->Next;
  2006. NdisQueryBufferSafe (OldNdisBuffer, NULL, &CurrentByteCount, HighPagePriority);
  2007. while (OldNdisBuffer != NULL) {
  2008. AvailableBytes = DesiredLength - BytesCopied;
  2009. if (AvailableBytes > CurrentByteCount) {
  2010. AvailableBytes = CurrentByteCount;
  2011. }
  2012. NdisCopyBuffer(
  2013. &NdisStatus,
  2014. &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
  2015. BufferPoolHandle,
  2016. OldNdisBuffer,
  2017. 0,
  2018. AvailableBytes);
  2019. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  2020. //
  2021. // ran out of resources. put back what we've used in this call and
  2022. // return the error.
  2023. //
  2024. while (*DestinationBuffer != NULL) {
  2025. NewNdisBuffer = NDIS_BUFFER_LINKAGE(*DestinationBuffer);
  2026. NdisFreeBuffer (*DestinationBuffer);
  2027. *DestinationBuffer = NewNdisBuffer;
  2028. }
  2029. *NewByteOffset = CurrentByteOffset;
  2030. *NewSourceBuffer = CurrentSourceBuffer;
  2031. return STATUS_INSUFFICIENT_RESOURCES;
  2032. }
  2033. NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
  2034. BytesCopied += AvailableBytes;
  2035. if (BytesCopied == DesiredLength) {
  2036. if (AvailableBytes == CurrentByteCount) {
  2037. *NewSourceBuffer = OldNdisBuffer->Next;
  2038. *NewByteOffset = 0;
  2039. } else {
  2040. *NewSourceBuffer = OldNdisBuffer;
  2041. *NewByteOffset = AvailableBytes;
  2042. }
  2043. *ActualLength = BytesCopied;
  2044. return STATUS_SUCCESS;
  2045. }
  2046. OldNdisBuffer = OldNdisBuffer->Next;
  2047. NdisQueryBufferSafe (OldNdisBuffer, NULL, &CurrentByteCount, HighPagePriority);
  2048. }
  2049. //
  2050. // We ran out of source buffer chain.
  2051. //
  2052. *NewSourceBuffer = NULL;
  2053. *NewByteOffset = 0;
  2054. *ActualLength = BytesCopied;
  2055. return STATUS_SUCCESS;
  2056. } /* NbiBuildBufferChainFromBufferChain */