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.

3380 lines
109 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. iframes.c
  5. Abstract:
  6. This module contains routines called to handle i-frames received
  7. from the data link provider. Most of these routines are called at receive
  8. indication time.
  9. Also included here are routines that process data at receive completion
  10. time. These are limited to handling DFM/DOL frames.
  11. The following frame types are cracked by routines in this module:
  12. o NBF_CMD_DATA_ACK
  13. o NBF_CMD_DATA_FIRST_MIDDLE
  14. o NBF_CMD_DATA_ONLY_LAST
  15. o NBF_CMD_SESSION_CONFIRM
  16. o NBF_CMD_SESSION_END
  17. o NBF_CMD_SESSION_INITIALIZE
  18. o NBF_CMD_NO_RECEIVE
  19. o NBF_CMD_RECEIVE_OUTSTANDING
  20. o NBF_CMD_RECEIVE_CONTINUE
  21. o NBF_CMD_SESSION_ALIVE
  22. Author:
  23. David Beaver (dbeaver) 1-July-1991
  24. Environment:
  25. Kernel mode, DISPATCH_LEVEL.
  26. Revision History:
  27. --*/
  28. #include "precomp.h"
  29. #pragma hdrstop
  30. extern ULONG StartTimerDelayedAck;
  31. #define NbfUsePiggybackAcks 1
  32. #if DBG
  33. extern ULONG NbfDebugPiggybackAcks;
  34. #endif
  35. VOID
  36. NbfAcknowledgeDataOnlyLast(
  37. IN PTP_CONNECTION Connection,
  38. IN ULONG MessageLength
  39. )
  40. /*++
  41. Routine Description:
  42. This routine takes care of acknowledging a DOL which has
  43. been received. It either sends a DATA_ACK right away, or
  44. queues a request for a piggyback ack.
  45. NOTE: This routine is called with the connection spinlock
  46. held, and it returns with it released. IT MUST BE CALLED
  47. AT DPC LEVEL.
  48. Arguments:
  49. Connection - Pointer to a transport connection (TP_CONNECTION).
  50. MessageLength - the total length (including all DFMs and this
  51. DOL) of the message.
  52. Return Value:
  53. NTSTATUS - status of operation.
  54. --*/
  55. {
  56. PDEVICE_CONTEXT DeviceContext;
  57. //
  58. // Determine if we need to ack at all.
  59. //
  60. if (Connection->CurrentReceiveNoAck) {
  61. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  62. return;
  63. }
  64. //
  65. // Determine if a piggyback ack is feasible.
  66. //
  67. if (NbfUsePiggybackAcks &&
  68. Connection->CurrentReceiveAckQueueable) {
  69. //
  70. // The sender allows it, see if we want to.
  71. //
  72. #if 0
  73. //
  74. // First reset this variable, to be safe.
  75. //
  76. Connection->CurrentReceiveAckQueueable = FALSE;
  77. #endif
  78. //
  79. // For long sends, don't bother since these
  80. // often happen without back traffic.
  81. //
  82. if (MessageLength >= 8192L) {
  83. #if DBG
  84. if (NbfDebugPiggybackAcks) {
  85. NbfPrint0("M");
  86. }
  87. #endif
  88. goto NormalDataAck;
  89. }
  90. //
  91. // If there have been two receives in a row with
  92. // no sends in between, don't wait for back traffic.
  93. //
  94. if (Connection->ConsecutiveReceives >= 2) {
  95. #if DBG
  96. if (NbfDebugPiggybackAcks) {
  97. NbfPrint0("R");
  98. }
  99. #endif
  100. goto NormalDataAck;
  101. }
  102. //
  103. // Do not put a stopping connection on the DataAckQueue
  104. //
  105. if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
  106. #if DBG
  107. if (NbfDebugPiggybackAcks) {
  108. NbfPrint0("S");
  109. }
  110. #endif
  111. goto NormalDataAck;
  112. }
  113. //
  114. // Queue the piggyback ack request. If the timer expires
  115. // before a DFM or DOL is sent, a normal DATA ACK will
  116. // be sent.
  117. //
  118. // Connection->Header.TransmitCorrelator has already been filled in.
  119. //
  120. //
  121. // BAD! We shouldn't already have an ack queued.
  122. //
  123. ASSERT ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) == 0);
  124. KeQueryTickCount (&Connection->ConnectStartTime);
  125. Connection->DeferredFlags |= CONNECTION_FLAGS_DEFERRED_ACK;
  126. #if DBG
  127. if (NbfDebugPiggybackAcks) {
  128. NbfPrint0("Q");
  129. }
  130. #endif
  131. DeviceContext = Connection->Link->Provider;
  132. if (!Connection->OnDataAckQueue) {
  133. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  134. if (!Connection->OnDataAckQueue) {
  135. Connection->OnDataAckQueue = TRUE;
  136. InsertTailList (&DeviceContext->DataAckQueue, &Connection->DataAckLinkage);
  137. if (!(DeviceContext->a.i.DataAckQueueActive)) {
  138. StartTimerDelayedAck++;
  139. NbfStartShortTimer (DeviceContext);
  140. DeviceContext->a.i.DataAckQueueActive = TRUE;
  141. }
  142. }
  143. RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  144. }
  145. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  146. INCREMENT_COUNTER (DeviceContext, PiggybackAckQueued);
  147. return;
  148. }
  149. NormalDataAck:;
  150. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  151. NbfSendDataAck (Connection);
  152. } /* NbfAcknowledgeDataOnlyLast */
  153. NTSTATUS
  154. ProcessSessionConfirm(
  155. IN PTP_CONNECTION Connection,
  156. IN PNBF_HDR_CONNECTION IFrame
  157. )
  158. /*++
  159. Routine Description:
  160. This routine handles an incoming SESSION_CONFIRM NetBIOS frame.
  161. Arguments:
  162. Connection - Pointer to a transport connection (TP_CONNECTION).
  163. IFrame - Pointer to NetBIOS connection-oriented header.
  164. Return Value:
  165. NTSTATUS - status of operation.
  166. --*/
  167. {
  168. KIRQL cancelirql;
  169. PLIST_ENTRY p;
  170. PTP_REQUEST request;
  171. PTDI_CONNECTION_INFORMATION remoteInformation;
  172. USHORT HisMaxDataSize;
  173. NTSTATUS status;
  174. PIO_STACK_LOCATION irpSp;
  175. ULONG returnLength;
  176. TA_NETBIOS_ADDRESS TempAddress;
  177. // BOOLEAN TimerWasSet;
  178. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  179. NbfPrint1 ("ProcessSessionConfirm: Entered, Flags: %lx\n", Connection->Flags);
  180. }
  181. Connection->IndicationInProgress = FALSE;
  182. IoAcquireCancelSpinLock (&cancelirql);
  183. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  184. if ((Connection->Flags & CONNECTION_FLAGS_WAIT_SC) != 0) {
  185. Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SC;
  186. //
  187. // Get his capability bits and maximum frame size.
  188. //
  189. if (IFrame->Data1 & SESSION_CONFIRM_OPTIONS_20) {
  190. Connection->Flags |= CONNECTION_FLAGS_VERSION2;
  191. }
  192. if (Connection->Link->Loopback) {
  193. Connection->MaximumDataSize = 0x8000;
  194. } else {
  195. Connection->MaximumDataSize = (USHORT)
  196. (Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME));
  197. HisMaxDataSize = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
  198. if (HisMaxDataSize < Connection->MaximumDataSize) {
  199. Connection->MaximumDataSize = HisMaxDataSize;
  200. }
  201. }
  202. //
  203. // Build a standard Netbios header for speed when sending
  204. // data frames.
  205. //
  206. ConstructDataOnlyLast(
  207. &Connection->NetbiosHeader,
  208. FALSE,
  209. (USHORT)0,
  210. Connection->Lsn,
  211. Connection->Rsn);
  212. //
  213. // Turn off the connection request timer if there is one, and set
  214. // this connection's state to READY.
  215. //
  216. Connection->Flags |= CONNECTION_FLAGS_READY;
  217. INCREMENT_COUNTER (Connection->Provider, OpenConnections);
  218. //
  219. // Record that the connect request has been successfully
  220. // completed by TpCompleteRequest.
  221. //
  222. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  223. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  224. Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
  225. if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
  226. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  227. Connection->IndicationInProgress = FALSE;
  228. IoReleaseCancelSpinLock (cancelirql);
  229. return STATUS_SUCCESS;
  230. }
  231. //
  232. // Complete the TdiConnect request.
  233. //
  234. p = RemoveHeadList (&Connection->InProgressRequest);
  235. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  236. //
  237. // Now complete the request and get out.
  238. //
  239. if (p == &Connection->InProgressRequest) {
  240. Connection->IndicationInProgress = FALSE;
  241. IoReleaseCancelSpinLock (cancelirql);
  242. return STATUS_SUCCESS;
  243. }
  244. //
  245. // We have a completed connection with a queued connect. Complete
  246. // the connect.
  247. //
  248. request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  249. IoSetCancelRoutine(request->IoRequestPacket, NULL);
  250. IoReleaseCancelSpinLock(cancelirql);
  251. irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
  252. remoteInformation =
  253. ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
  254. if (remoteInformation != NULL) {
  255. try {
  256. if (remoteInformation->RemoteAddressLength != 0) {
  257. //
  258. // Build a temporary TA_NETBIOS_ADDRESS, then
  259. // copy over as many bytes as fit.
  260. //
  261. TdiBuildNetbiosAddress(
  262. Connection->CalledAddress.NetbiosName,
  263. (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
  264. TDI_ADDRESS_NETBIOS_TYPE_GROUP),
  265. &TempAddress);
  266. if (remoteInformation->RemoteAddressLength >=
  267. sizeof (TA_NETBIOS_ADDRESS)) {
  268. returnLength = sizeof(TA_NETBIOS_ADDRESS);
  269. remoteInformation->RemoteAddressLength = returnLength;
  270. } else {
  271. returnLength = remoteInformation->RemoteAddressLength;
  272. }
  273. RtlCopyMemory(
  274. (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
  275. &TempAddress,
  276. returnLength);
  277. } else {
  278. returnLength = 0;
  279. }
  280. status = STATUS_SUCCESS;
  281. } except (EXCEPTION_EXECUTE_HANDLER) {
  282. returnLength = 0;
  283. status = GetExceptionCode ();
  284. }
  285. } else {
  286. status = STATUS_SUCCESS;
  287. returnLength = 0;
  288. }
  289. if (status == STATUS_SUCCESS) {
  290. if ((ULONG)Connection->Retries == Connection->Provider->NameQueryRetries) {
  291. INCREMENT_COUNTER (Connection->Provider, ConnectionsAfterNoRetry);
  292. } else {
  293. INCREMENT_COUNTER (Connection->Provider, ConnectionsAfterRetry);
  294. }
  295. }
  296. //
  297. // Don't clear this until now, so that the connection is all
  298. // set up before we allow more indications.
  299. //
  300. Connection->IndicationInProgress = FALSE;
  301. NbfCompleteRequest (request, status, returnLength);
  302. } else {
  303. Connection->IndicationInProgress = FALSE;
  304. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  305. IoReleaseCancelSpinLock(cancelirql);
  306. }
  307. return STATUS_SUCCESS;
  308. } /* ProcessSessionConfirm */
  309. NTSTATUS
  310. ProcessSessionEnd(
  311. IN PTP_CONNECTION Connection,
  312. IN PNBF_HDR_CONNECTION IFrame
  313. )
  314. /*++
  315. Routine Description:
  316. This routine handles an incoming SESSION_END NetBIOS frame.
  317. Arguments:
  318. Connection - Pointer to a transport connection (TP_CONNECTION).
  319. IFrame - Pointer to NetBIOS connection-oriented header.
  320. Return Value:
  321. NTSTATUS - status of operation.
  322. --*/
  323. {
  324. USHORT data2;
  325. NTSTATUS StopStatus;
  326. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  327. NbfPrint0 ("ProcessSessionEnd: Entered.\n");
  328. }
  329. //
  330. // Handle the error code in the Data2 field. Current protocol says
  331. // if the field is 0, then this is a normal HANGUP.NCB operation.
  332. // If the field is 1, then this is an abnormal session end, caused
  333. // by something like a SEND.NCB timing out. Of course, new protocol
  334. // may be added in the future, so we handle only these specific cases.
  335. //
  336. data2 = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
  337. switch (data2) {
  338. case 0:
  339. case 1:
  340. StopStatus = STATUS_REMOTE_DISCONNECT;
  341. break;
  342. default:
  343. PANIC ("ProcessSessionEnd: frame not expected.\n");
  344. StopStatus = STATUS_INVALID_NETWORK_RESPONSE;
  345. }
  346. #if DBG
  347. if (NbfDisconnectDebug) {
  348. STRING remoteName, localName;
  349. remoteName.Length = NETBIOS_NAME_LENGTH - 1;
  350. remoteName.Buffer = Connection->RemoteName;
  351. localName.Length = NETBIOS_NAME_LENGTH - 1;
  352. localName.Buffer = Connection->AddressFile->Address->NetworkName->NetbiosName;
  353. NbfPrint3( "SessionEnd received for connection to %S from %S; reason %s\n",
  354. &remoteName, &localName,
  355. data2 == 0 ? "NORMAL" : data2 == 1 ? "ABORT" : "UNKNOWN" );
  356. }
  357. #endif
  358. //
  359. // Run-down this connection.
  360. //
  361. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  362. NbfPrint0 ("ProcessSessionEnd calling NbfStopConnection\n");
  363. }
  364. NbfStopConnection (Connection, StopStatus); // disconnected by the other end
  365. Connection->IndicationInProgress = FALSE;
  366. return STATUS_SUCCESS;
  367. } /* ProcessSessionEnd */
  368. NTSTATUS
  369. ProcessSessionInitialize(
  370. IN PTP_CONNECTION Connection,
  371. IN PNBF_HDR_CONNECTION IFrame
  372. )
  373. /*++
  374. Routine Description:
  375. This routine handles an incoming SESSION_INITIALIZE NetBIOS frame.
  376. Arguments:
  377. Connection - Pointer to a transport connection (TP_CONNECTION).
  378. IFrame - Pointer to NetBIOS connection-oriented header.
  379. Return Value:
  380. NTSTATUS - status of operation.
  381. --*/
  382. {
  383. KIRQL cancelirql;
  384. PLIST_ENTRY p;
  385. PTP_REQUEST request;
  386. PIO_STACK_LOCATION irpSp;
  387. USHORT HisMaxDataSize;
  388. ULONG returnLength;
  389. PTDI_CONNECTION_INFORMATION remoteInformation;
  390. NTSTATUS status;
  391. TA_NETBIOS_ADDRESS TempAddress;
  392. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  393. NbfPrint1 ("ProcessSessionInitialize: Entered, Flags: %lx\n", Connection->Flags);
  394. }
  395. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  396. if ((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) {
  397. Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SI;
  398. //
  399. // Get his capability bits and maximum frame size.
  400. //
  401. if (IFrame->Data1 & SESSION_INIT_OPTIONS_20) {
  402. Connection->Flags |= CONNECTION_FLAGS_VERSION2;
  403. }
  404. if (Connection->Link->Loopback) {
  405. Connection->MaximumDataSize = 0x8000;
  406. } else {
  407. Connection->MaximumDataSize = (USHORT)
  408. (Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME));
  409. HisMaxDataSize = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
  410. if (HisMaxDataSize < Connection->MaximumDataSize) {
  411. Connection->MaximumDataSize = HisMaxDataSize;
  412. }
  413. }
  414. //
  415. // Build a standard Netbios header for speed when sending
  416. // data frames.
  417. //
  418. ConstructDataOnlyLast(
  419. &Connection->NetbiosHeader,
  420. FALSE,
  421. (USHORT)0,
  422. Connection->Lsn,
  423. Connection->Rsn);
  424. //
  425. // Save his session initialize correlator so we can send it
  426. // in the session confirm frame.
  427. //
  428. Connection->NetbiosHeader.TransmitCorrelator = RESPONSE_CORR(IFrame);
  429. //
  430. // Turn off the connection request timer if there is one (we're done).
  431. // Do this with the lock held in case the connection is about to
  432. // be closed, to not interfere with the timer started when the
  433. // connection started then.
  434. //
  435. if (KeCancelTimer (&Connection->Timer)) {
  436. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  437. NbfDereferenceConnection ("Timer canceled", Connection, CREF_TIMER); // remove timer reference.
  438. } else {
  439. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  440. }
  441. //
  442. // Now, complete the listen request on the connection (if there was
  443. // one) and continue with as much of the protocol request as possible.
  444. // if the user has "pre-accepted" the connection, we'll just continue
  445. // onward here and complete the entire connection setup. If the user
  446. // was indicated and has not yet accepted, we'll just put the
  447. // connection into the proper state and fall out the bottom without
  448. // completing anything.
  449. //
  450. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  451. if (((Connection->Flags2 & CONNECTION_FLAGS2_ACCEPTED) != 0) ||
  452. ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) != 0)) {
  453. IF_NBFDBG (NBF_DEBUG_SETUP) {
  454. NbfPrint1("SessionInitialize: Accepted connection %lx\n", Connection);
  455. }
  456. //
  457. // we've already accepted the connection; allow it to proceed.
  458. // this is the normal path for kernel mode indication clients,
  459. // or for those who don't specify TDI_QUERY_ACCEPT on the listen.
  460. //
  461. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  462. Connection->Flags |= CONNECTION_FLAGS_READY;
  463. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  464. INCREMENT_COUNTER (Connection->Provider, OpenConnections);
  465. //
  466. // Record that the listen request has been successfully
  467. // completed by NbfCompleteRequest.
  468. //
  469. Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
  470. status = STATUS_SUCCESS;
  471. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  472. NbfSendSessionConfirm (Connection);
  473. } else {
  474. if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
  475. //
  476. // we disconnected, destroy the connection
  477. //
  478. IF_NBFDBG (NBF_DEBUG_SETUP) {
  479. NbfPrint1("SessionInitialize: Disconnected connection %lx\n", Connection);
  480. }
  481. status = STATUS_LOCAL_DISCONNECT;
  482. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  483. NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
  484. } else {
  485. //
  486. // we've done nothing, wait for the user to accept on this
  487. // connection. This is the "normal" path for non-indication
  488. // clients.
  489. //
  490. Connection->Flags2 |= CONNECTION_FLAGS2_WAITING_SC;
  491. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  492. status = STATUS_SUCCESS;
  493. }
  494. }
  495. //
  496. // Now, if there was no queued listen, we have done everything we can
  497. // for this connection, so we simply exit and leave everything up to
  498. // the user. If we've gotten an indication response that allows the
  499. // connection to proceed, we will come out of here with a connection
  500. // that's up and running.
  501. //
  502. IoAcquireCancelSpinLock (&cancelirql);
  503. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  504. p = RemoveHeadList (&Connection->InProgressRequest);
  505. if (p == &Connection->InProgressRequest) {
  506. Connection->IndicationInProgress = FALSE;
  507. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  508. IoReleaseCancelSpinLock (cancelirql);
  509. return STATUS_SUCCESS;
  510. }
  511. //
  512. // We have a completed connection with a queued listen. Complete
  513. // the listen and let the user do an accept at some time down the
  514. // road.
  515. //
  516. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  517. request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  518. IoSetCancelRoutine(request->IoRequestPacket, NULL);
  519. IoReleaseCancelSpinLock (cancelirql);
  520. irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
  521. remoteInformation =
  522. ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
  523. if (remoteInformation != NULL) {
  524. try {
  525. if (remoteInformation->RemoteAddressLength != 0) {
  526. //
  527. // Build a temporary TA_NETBIOS_ADDRESS, then
  528. // copy over as many bytes as fit.
  529. //
  530. TdiBuildNetbiosAddress(
  531. Connection->CalledAddress.NetbiosName,
  532. (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
  533. TDI_ADDRESS_NETBIOS_TYPE_GROUP),
  534. &TempAddress);
  535. if (remoteInformation->RemoteAddressLength >=
  536. sizeof (TA_NETBIOS_ADDRESS)) {
  537. returnLength = sizeof(TA_NETBIOS_ADDRESS);
  538. remoteInformation->RemoteAddressLength = returnLength;
  539. } else {
  540. returnLength = remoteInformation->RemoteAddressLength;
  541. }
  542. RtlCopyMemory(
  543. (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
  544. &TempAddress,
  545. returnLength);
  546. } else {
  547. returnLength = 0;
  548. }
  549. status = STATUS_SUCCESS;
  550. } except (EXCEPTION_EXECUTE_HANDLER) {
  551. returnLength = 0;
  552. status = GetExceptionCode ();
  553. }
  554. } else {
  555. status = STATUS_SUCCESS;
  556. returnLength = 0;
  557. }
  558. //
  559. // Don't clear this until now, so that the connection is all
  560. // set up before we allow more indications.
  561. //
  562. Connection->IndicationInProgress = FALSE;
  563. NbfCompleteRequest (request, status, 0);
  564. } else {
  565. Connection->IndicationInProgress = FALSE;
  566. #if DBG
  567. NbfPrint3 ("ProcessSessionInitialize: C %lx, Flags %lx, Flags2 %lx\n",
  568. Connection, Connection->Flags, Connection->Flags2);
  569. #endif
  570. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  571. }
  572. return STATUS_SUCCESS;
  573. } /* ProcessSessionInitialize */
  574. NTSTATUS
  575. ProcessNoReceive(
  576. IN PTP_CONNECTION Connection,
  577. IN PNBF_HDR_CONNECTION IFrame
  578. )
  579. /*++
  580. Routine Description:
  581. This routine handles an incoming NO_RECEIVE NetBIOS frame.
  582. NOTE: This routine is called with the connection spinlock
  583. held and returns with it released.
  584. Arguments:
  585. Connection - Pointer to a transport connection (TP_CONNECTION).
  586. IFrame - Pointer to NetBIOS connection-oriented header.
  587. Return Value:
  588. NTSTATUS - status of operation.
  589. --*/
  590. {
  591. UNREFERENCED_PARAMETER (IFrame); // prevent compiler warnings
  592. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  593. NbfPrint0 ("ProcessNoReceive: Entered.\n");
  594. }
  595. switch (Connection->SendState) {
  596. case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
  597. case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
  598. case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
  599. case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
  600. case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
  601. // Connection->SendState = CONNECTION_SENDSTATE_W_RCVCONT;
  602. //
  603. // this used to be here, and is right for the other side of the connection. It's
  604. // wrong here.
  605. // Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
  606. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  607. ReframeSend (Connection, IFrame->Data2Low + IFrame->Data2High*256);
  608. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  609. break;
  610. case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
  611. case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
  612. PANIC ("ProcessNoReceive: Frame not expected.\n");
  613. break;
  614. default:
  615. PANIC ("ProcessNoReceive: Invalid SendState.\n");
  616. }
  617. //
  618. // Don't clear this until ReframeSend has been called
  619. //
  620. Connection->IndicationInProgress = FALSE;
  621. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  622. return STATUS_SUCCESS;
  623. } /* ProcessNoReceive */
  624. NTSTATUS
  625. ProcessReceiveOutstanding(
  626. IN PTP_CONNECTION Connection,
  627. IN PNBF_HDR_CONNECTION IFrame
  628. )
  629. /*++
  630. Routine Description:
  631. This routine handles an incoming RECEIVE_OUTSTANDING NetBIOS frame.
  632. NOTE: This routine is called with the connection spinlock
  633. held and returns with it released.
  634. Arguments:
  635. Connection - Pointer to a transport connection (TP_CONNECTION).
  636. IFrame - Pointer to NetBIOS connection-oriented header.
  637. Return Value:
  638. NTSTATUS - status of operation.
  639. --*/
  640. {
  641. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  642. NbfPrint0 ("ProcessReceiveOutstanding: Entered.\n");
  643. }
  644. switch (Connection->SendState) {
  645. case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
  646. case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
  647. case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
  648. case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
  649. case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
  650. case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
  651. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  652. ReframeSend (Connection, IFrame->Data2Low + IFrame->Data2High*256);
  653. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  654. if ((Connection->Flags & CONNECTION_FLAGS_READY) != 0) {
  655. Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
  656. Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
  657. }
  658. break;
  659. case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
  660. PANIC ("ProcessReceiveOutstanding: Frame not expected.\n");
  661. break;
  662. default:
  663. PANIC ("ProcessReceiveOutstanding: Invalid SendState.\n");
  664. }
  665. //
  666. // Don't clear this until ReframeSend has been called
  667. //
  668. Connection->IndicationInProgress = FALSE;
  669. //
  670. // Now start packetizing the connection again since we've reframed
  671. // the current send. If we were idle or in a bad state, then the
  672. // packetizing routine will detect that.
  673. //
  674. // *** StartPacketizingConnection releases the Connection spin lock.
  675. //
  676. StartPacketizingConnection (Connection, FALSE);
  677. return STATUS_SUCCESS;
  678. } /* ProcessReceiveOutstanding */
  679. NTSTATUS
  680. ProcessReceiveContinue(
  681. IN PTP_CONNECTION Connection,
  682. IN PNBF_HDR_CONNECTION IFrame
  683. )
  684. /*++
  685. Routine Description:
  686. This routine handles an incoming RECEIVE_CONTINUE NetBIOS frame.
  687. NOTE: This routine is called with the connection spinlock
  688. held and returns with it released.
  689. Arguments:
  690. Connection - Pointer to a transport connection (TP_CONNECTION).
  691. IFrame - Pointer to NetBIOS connection-oriented header.
  692. Return Value:
  693. NTSTATUS - status of operation.
  694. --*/
  695. {
  696. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  697. NbfPrint0 ("ProcessReceiveContinue: Entered.\n");
  698. }
  699. switch (Connection->SendState) {
  700. case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
  701. case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
  702. case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
  703. case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
  704. case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
  705. case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
  706. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  707. ReframeSend (Connection, Connection->sp.MessageBytesSent);
  708. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  709. Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
  710. Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
  711. break;
  712. case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
  713. PANIC ("ProcessReceiveContinue: Frame not expected.\n");
  714. break;
  715. default:
  716. PANIC ("ProcessReceiveContinue: Invalid SendState.\n");
  717. }
  718. //
  719. // Don't clear this until ReframeSend has been called
  720. //
  721. Connection->IndicationInProgress = FALSE;
  722. //
  723. // Now start packetizing the connection again since we've reframed
  724. // the current send. If we were idle or in a bad state, then the
  725. // packetizing routine will detect that.
  726. //
  727. // *** StartPacketizingConnection releases the Connection spin lock.
  728. //
  729. StartPacketizingConnection (Connection, FALSE);
  730. return STATUS_SUCCESS;
  731. } /* ProcessReceiveContinue */
  732. NTSTATUS
  733. ProcessSessionAlive(
  734. IN PTP_CONNECTION Connection,
  735. IN PNBF_HDR_CONNECTION IFrame
  736. )
  737. /*++
  738. Routine Description:
  739. This routine handles an incoming SESSION_ALIVE NetBIOS frame. This
  740. routine is by far the simplest in the transport because it does nothing.
  741. The SESSION_ALIVE frame is simply a dummy frame that is sent on the
  742. reliable data link layer to determine if the data link is still active;
  743. no NetBIOS level protocol processing is performed.
  744. Arguments:
  745. Connection - Pointer to a transport connection (TP_CONNECTION).
  746. IFrame - Pointer to NetBIOS connection-oriented header.
  747. Return Value:
  748. NTSTATUS - status of operation.
  749. --*/
  750. {
  751. UNREFERENCED_PARAMETER (Connection); // prevent compiler warnings
  752. UNREFERENCED_PARAMETER (IFrame); // prevent compiler warnings
  753. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  754. NbfPrint0 ("ProcessSessionAlive: Entered.\n");
  755. }
  756. Connection->IndicationInProgress = FALSE;
  757. return STATUS_SUCCESS;
  758. } /* ProcessSessionAlive */
  759. VOID
  760. NbfProcessIIndicate(
  761. IN BOOLEAN Command,
  762. IN BOOLEAN PollFinal,
  763. IN PTP_LINK Link,
  764. IN PUCHAR DlcHeader,
  765. IN UINT DlcIndicatedLength,
  766. IN UINT DlcTotalLength,
  767. IN NDIS_HANDLE ReceiveContext,
  768. IN BOOLEAN Loopback
  769. )
  770. /*++
  771. Routine Description:
  772. This routine processes a received I frame at indication time. It will do
  773. all necessary verification processing of the frame and pass those frames
  774. that are valid on to the proper handling routines.
  775. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  776. Arguments:
  777. Command - Boolean set to TRUE if command, else FALSE if response.
  778. PollFinal - Boolean set to TRUE if Poll or Final.
  779. Link - Pointer to a transport link object.
  780. Header - Pointer to a DLC I-type frame.
  781. DlcHeader - A pointer to the start of the DLC header in the packet.
  782. DlcIndicatedLength - The length of the packet indicated, starting at
  783. DlcHeader.
  784. DlcTotalLength - The total length of the packet, starting at DlcHeader.
  785. ReceiveContext - A magic value for NDIS that indicates which packet we're
  786. talking about.
  787. Loopback - Is this a loopback indication; used to determine whether
  788. to call NdisTransferData or NbfTransferLoopbackData.
  789. Return Value:
  790. None.
  791. --*/
  792. {
  793. #if DBG
  794. UCHAR *s;
  795. #endif
  796. PNBF_HDR_CONNECTION nbfHeader;
  797. PDLC_I_FRAME header;
  798. NTSTATUS Status;
  799. UCHAR lsn, rsn;
  800. PTP_CONNECTION connection;
  801. PUCHAR DataHeader;
  802. ULONG DataTotalLength;
  803. PLIST_ENTRY p;
  804. BOOLEAN ConnectionFound;
  805. IF_NBFDBG (NBF_DEBUG_DLC) {
  806. NbfPrint0 (" NbfProcessIIndicate: Entered.\n");
  807. }
  808. //
  809. // Process any of: I-x/x.
  810. //
  811. header = (PDLC_I_FRAME)DlcHeader;
  812. nbfHeader = (PNBF_HDR_CONNECTION)((PUCHAR)header + 4); // skip DLC hdr.
  813. //
  814. // Verify signatures. We test the signature as a 16-bit
  815. // word as specified in the NetBIOS Formats and Protocols manual,
  816. // with the assert guarding us against big-endian systems.
  817. //
  818. ASSERT ((((PUCHAR)(&nbfHeader->Length))[0] + ((PUCHAR)(&nbfHeader->Length))[1]*256) ==
  819. HEADER_LENGTH(nbfHeader));
  820. if (HEADER_LENGTH(nbfHeader) != sizeof(NBF_HDR_CONNECTION)) {
  821. IF_NBFDBG (NBF_DEBUG_DLC) {
  822. NbfPrint0 ("NbfProcessIIndicate: Dropped I frame, Too short or long.\n");
  823. }
  824. return; // frame too small or too large.
  825. }
  826. if (HEADER_SIGNATURE(nbfHeader) != NETBIOS_SIGNATURE) {
  827. IF_NBFDBG (NBF_DEBUG_DLC) {
  828. NbfPrint0 ("NbfProcessIIndicate: Dropped I frame, Signature bad.\n");
  829. }
  830. return; // invalid signature in frame.
  831. }
  832. DataHeader = (PUCHAR)DlcHeader + (4 + sizeof(NBF_HDR_CONNECTION));
  833. DataTotalLength = DlcTotalLength - (4 + sizeof(NBF_HDR_CONNECTION));
  834. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  835. switch (Link->State) {
  836. case LINK_STATE_READY:
  837. //
  838. // Link is balanced. This code is extremely critical since
  839. // it is the most-covered path in the system for small and
  840. // large I/O. Be very careful in adding code here as it will
  841. // seriously affect the overall performance of the LAN. It is
  842. // first in the list of possible states for that reason.
  843. //
  844. #if DBG
  845. s = "READY";
  846. #endif
  847. Link->LinkBusy = FALSE;
  848. //
  849. // The I-frame's N(S) should match our V(R). If it
  850. // doesn't, issue a reject. Otherwise, increment our V(R).
  851. //
  852. if ((UCHAR)((header->SendSeq >> 1) & 0x7F) != Link->NextReceive) {
  853. IF_NBFDBG (NBF_DEBUG_DLC) {
  854. NbfPrint0 (" NbfProcessIIndicate: N(S) != V(R).\n");
  855. }
  856. if (Link->ReceiveState == RECEIVE_STATE_REJECTING) {
  857. //
  858. // We already sent a reject, only respond if
  859. // he is polling.
  860. //
  861. if (Command & PollFinal) {
  862. NbfSendRr(Link, FALSE, TRUE); // releases lock
  863. } else {
  864. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  865. }
  866. } else {
  867. Link->ReceiveState = RECEIVE_STATE_REJECTING;
  868. //
  869. // NbfSendRej releases the spinlock.
  870. //
  871. if (Command) {
  872. NbfSendRej (Link, FALSE, PollFinal);
  873. } else {
  874. NbfSendRej (Link, FALSE, FALSE);
  875. }
  876. }
  877. //
  878. // Update our "bytes rejected" counters.
  879. //
  880. ADD_TO_LARGE_INTEGER(
  881. &Link->Provider->Statistics.DataFrameBytesRejected,
  882. DataTotalLength);
  883. ++Link->Provider->Statistics.DataFramesRejected;
  884. //
  885. // Discard this packet.
  886. //
  887. break;
  888. }
  889. //
  890. // Find the transport connection object associated with this frame.
  891. // Because there may be several NetBIOS (transport) connections
  892. // over the same data link connection, and the ConnectionContext
  893. // value represents a data link connection to a specific address,
  894. // we simply use the RSN field in the frame to index into the
  895. // connection database for this link object.
  896. //
  897. // We do this before processing the rest of the LLC header,
  898. // in case the connection is busy and we have to ignore
  899. // the frame.
  900. //
  901. ConnectionFound = FALSE;
  902. lsn = nbfHeader->DestinationSessionNumber;
  903. rsn = nbfHeader->SourceSessionNumber;
  904. if ((lsn == 0) || (lsn > NETBIOS_SESSION_LIMIT)) {
  905. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  906. NbfPrint0 ("NbfProcessIIndicate: Invalid LSN.\n");
  907. }
  908. } else {
  909. p = Link->ConnectionDatabase.Flink;
  910. while (p != &Link->ConnectionDatabase) {
  911. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  912. if (connection->Lsn >= lsn) { // assumes ordered list
  913. break;
  914. }
  915. p = p->Flink;
  916. }
  917. // Don't use compound if 'cause Connection may be garbage
  918. if (p == &Link->ConnectionDatabase) {
  919. #if DBG
  920. NbfPrint2 ("NbfProcessIIndicate: Connection not found in database: \n Lsn %x Link %lx",
  921. lsn, Link);
  922. NbfPrint6 ("Remote: %x-%x-%x-%x-%x-%x\n",
  923. Link->HardwareAddress.Address[0], Link->HardwareAddress.Address[1],
  924. Link->HardwareAddress.Address[2], Link->HardwareAddress.Address[3],
  925. Link->HardwareAddress.Address[4], Link->HardwareAddress.Address[5]);
  926. #endif
  927. } else if (connection->Lsn != lsn) {
  928. #if DBG
  929. NbfPrint0 ("NbfProcessIIndicate: Connection in database doesn't match.\n");
  930. #endif
  931. } else if (connection->Rsn != rsn) {
  932. #if DBG
  933. NbfPrint3 ("NbfProcessIIndicate: Connection lsn %d had rsn %d, got frame for %d\n",
  934. connection->Lsn, connection->Rsn, rsn);
  935. #endif
  936. } else {
  937. //
  938. // The connection is good, proceed.
  939. //
  940. ConnectionFound = TRUE;
  941. if (connection->IndicationInProgress) {
  942. NbfPrint1("ProcessIIndicate: Indication in progress on %lx\n", connection);
  943. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  944. return;
  945. }
  946. //
  947. // Set this, it prevents other I-frames from being received
  948. // on this connection. The various ProcessXXX routines
  949. // that are called from the switch below will clear
  950. // this flag when they determine it is OK to be reentered.
  951. //
  952. connection->IndicationInProgress = TRUE;
  953. // This reference is removed before this function returns or
  954. // we are done with the LINK_STATE_READY part of the outer switch.
  955. NbfReferenceConnection ("Processing IFrame", connection, CREF_PROCESS_DATA);
  956. }
  957. }
  958. #if PKT_LOG
  959. if (ConnectionFound) {
  960. // We have the connection here, log the packet for debugging
  961. NbfLogRcvPacket(connection,
  962. NULL,
  963. DlcHeader,
  964. DlcTotalLength,
  965. DlcIndicatedLength);
  966. }
  967. else {
  968. // We just have the link here, log the packet for debugging
  969. NbfLogRcvPacket(NULL,
  970. Link,
  971. DlcHeader,
  972. DlcTotalLength,
  973. DlcIndicatedLength);
  974. }
  975. #endif // PKT_LOG
  976. //
  977. // As long as we don't have to drop this frame, adjust the link
  978. // state correctly. If ConnectionFound is FALSE, then we exit
  979. // right after doing this.
  980. //
  981. //
  982. // The I-frame we expected arrived, clear rejecting state.
  983. //
  984. if (Link->ReceiveState == RECEIVE_STATE_REJECTING) {
  985. Link->ReceiveState = RECEIVE_STATE_READY;
  986. }
  987. Link->NextReceive = (UCHAR)((Link->NextReceive+1) & 0x7f);
  988. //
  989. // If he is checkpointing, we need to respond with RR-c/f. If
  990. // we respond, then stop the delayed ack timer. Otherwise, we
  991. // need to start it because this is an I-frame that will not be
  992. // acked immediately.
  993. //
  994. if (Command && PollFinal) {
  995. IF_NBFDBG (NBF_DEBUG_DLC) {
  996. NbfPrint0 (" NbfProcessI: he's checkpointing.\n");
  997. }
  998. Link->RemoteNoPoll = FALSE;
  999. StopT2 (Link); // we're acking, so no delay req'd.
  1000. NbfSendRr (Link, FALSE, TRUE); // releases lock
  1001. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1002. } else {
  1003. if (Link->RemoteNoPoll) {
  1004. if ((++Link->ConsecutiveIFrames) == Link->Provider->MaxConsecutiveIFrames) {
  1005. //
  1006. // This appears to be one of those remotes which
  1007. // never polls, so we send an RR if there are two
  1008. // frames outstanding (StopT2 sets ConsecutiveIFrames
  1009. // to 0).
  1010. //
  1011. StopT2 (Link); // we're acking, so no delay req'd.
  1012. NbfSendRr (Link, FALSE, FALSE); // releases lock
  1013. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1014. } else {
  1015. StartT2 (Link);
  1016. ACQUIRE_DPC_SPIN_LOCK (&Link->Provider->Interlock);
  1017. if (!Link->OnDeferredRrQueue) {
  1018. InsertTailList(
  1019. &Link->Provider->DeferredRrQueue,
  1020. &Link->DeferredRrLinkage);
  1021. Link->OnDeferredRrQueue = TRUE;
  1022. }
  1023. RELEASE_DPC_SPIN_LOCK (&Link->Provider->Interlock);
  1024. }
  1025. } else {
  1026. StartT2 (Link); // start delayed ack sequence.
  1027. }
  1028. //
  1029. // If he is responding to a checkpoint, we need to clear our
  1030. // send state. Any packets which are still waiting for acknowlegement
  1031. // at this point must now be resent.
  1032. //
  1033. if ((!Command) && PollFinal) {
  1034. IF_NBFDBG (NBF_DEBUG_DLC) {
  1035. NbfPrint0 (" NbfProcessI: he's responding to our checkpoint.\n");
  1036. }
  1037. if (Link->SendState != SEND_STATE_CHECKPOINTING) {
  1038. IF_NBFDBG (NBF_DEBUG_DLC) {
  1039. NbfPrint1 (" NbfProcessI: Ckpt but SendState=%ld.\n",
  1040. Link->SendState);
  1041. }
  1042. }
  1043. StopT1 (Link); // checkpoint completed.
  1044. Link->SendState = SEND_STATE_READY;
  1045. StartTi (Link);
  1046. }
  1047. }
  1048. //
  1049. // Now, if we could not find the connection or the sequence
  1050. // numbers did not match, return. We don't call ResendLlcPackets
  1051. // in this case, but that is OK (eventually we will poll).
  1052. //
  1053. if (!ConnectionFound) {
  1054. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1055. return;
  1056. }
  1057. ASSERT (connection->LinkSpinLock == &Link->SpinLock);
  1058. //
  1059. // The N(R) in this frame may acknowlege some WackQ packets.
  1060. // We delay checking this until after processing the I-frame,
  1061. // so that we can get IndicationInProgress set to FALSE
  1062. // before we start resending the WackQ.
  1063. //
  1064. switch (nbfHeader->Command) {
  1065. case NBF_CMD_DATA_FIRST_MIDDLE:
  1066. case NBF_CMD_DATA_ONLY_LAST:
  1067. //
  1068. // First see if this packet has a piggyback ack -- we process
  1069. // this even if we throw the packet away below.
  1070. //
  1071. // This is a bit ugly since theoretically the piggyback
  1072. // ack bits in a DFM and a DOL could be different, but
  1073. // they aren't.
  1074. //
  1075. if (NbfUsePiggybackAcks) {
  1076. ASSERT (DFM_OPTIONS_ACK_INCLUDED == DOL_OPTIONS_ACK_INCLUDED);
  1077. if ((nbfHeader->Data1 & DFM_OPTIONS_ACK_INCLUDED) != 0) {
  1078. //
  1079. // This returns with the connection spinlock held
  1080. // but may release it and reacquire it.
  1081. //
  1082. CompleteSend(
  1083. connection,
  1084. TRANSMIT_CORR(nbfHeader));
  1085. }
  1086. }
  1087. //
  1088. // NOTE: The connection spinlock is held here.
  1089. //
  1090. //
  1091. // If the connection is not ready, drop the frame.
  1092. //
  1093. if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
  1094. connection->IndicationInProgress = FALSE;
  1095. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1096. Status = STATUS_SUCCESS;
  1097. goto SkipProcessIndicateData;
  1098. }
  1099. //
  1100. // A quick check for the three flags that are
  1101. // rarely set.
  1102. //
  1103. if ((connection->Flags & (CONNECTION_FLAGS_W_RESYNCH |
  1104. CONNECTION_FLAGS_RC_PENDING |
  1105. CONNECTION_FLAGS_RECEIVE_WAKEUP)) == 0) {
  1106. goto NoFlagsSet;
  1107. }
  1108. //
  1109. // If we are waiting for a resynch bit to be set in an
  1110. // incoming frame, toss the frame if it isn't set.
  1111. // Otherwise, clear the wait condition.
  1112. //
  1113. if (connection->Flags & CONNECTION_FLAGS_W_RESYNCH) {
  1114. if ((nbfHeader->Data2Low == 1) && (nbfHeader->Data2High == 0)) {
  1115. connection->Flags &= ~CONNECTION_FLAGS_W_RESYNCH;
  1116. } else {
  1117. connection->IndicationInProgress = FALSE;
  1118. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1119. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  1120. NbfPrint0 ("NbfProcessIIndicate: Discarded DFM/DOL, waiting for resynch.\n");
  1121. }
  1122. Status = STATUS_SUCCESS;
  1123. goto SkipProcessIndicateData;
  1124. }
  1125. }
  1126. //
  1127. // If we have a previous receive that is pending
  1128. // completion, then we need to ignore this frame.
  1129. // This may be common on MP, so rather than drop
  1130. // it and wait for a poll, we send a NO_RECEIVE,
  1131. // then a RCV_OUTSTANDING when we have some
  1132. // resources.
  1133. //
  1134. if (connection->Flags & CONNECTION_FLAGS_RC_PENDING) {
  1135. //
  1136. // Hack the connection object so the NO_RECEIVE
  1137. // looks right.
  1138. //
  1139. connection->MessageBytesReceived = 0;
  1140. connection->MessageBytesAcked = 0;
  1141. connection->MessageInitAccepted = 0;
  1142. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1143. NbfSendNoReceive (connection);
  1144. ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1145. //
  1146. // We now turn on the PEND_INDICATE flag to show
  1147. // that we need to send RCV_OUTSTANDING when the
  1148. // receive completes. If RC_PENDING is now off,
  1149. // it means the receive was just completed, so
  1150. // we ourselves need to send the RCV_OUTSTANDING.
  1151. //
  1152. if ((connection->Flags & CONNECTION_FLAGS_RC_PENDING) == 0) {
  1153. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1154. NbfSendReceiveOutstanding (connection);
  1155. ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1156. } else {
  1157. connection->Flags |= CONNECTION_FLAGS_PEND_INDICATE;
  1158. }
  1159. connection->IndicationInProgress = FALSE;
  1160. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1161. IF_NBFDBG (NBF_DEBUG_IFRAMES) {
  1162. NbfPrint0 ("NbfProcessIIndicate: Discarded DFM/DOL, receive complete pending.\n");
  1163. }
  1164. Status = STATUS_SUCCESS;
  1165. goto SkipProcessIndicateData;
  1166. }
  1167. //
  1168. // If we are discarding data received on this connection
  1169. // because we've sent a no receive, ditch it.
  1170. //
  1171. if (connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
  1172. connection->IndicationInProgress = FALSE;
  1173. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1174. NbfPrint0 ("NbfProcessIIndicate: In wakeup state, discarding frame.\n");
  1175. }
  1176. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1177. Status = STATUS_SUCCESS;
  1178. goto SkipProcessIndicateData;
  1179. }
  1180. NoFlagsSet:;
  1181. //
  1182. // The connection spinlock is held here.
  1183. //
  1184. if (nbfHeader->Command == NBF_CMD_DATA_FIRST_MIDDLE) {
  1185. //
  1186. // NOTE: This release connection->LinkSpinLock.
  1187. //
  1188. Status = ProcessIndicateData (
  1189. connection,
  1190. DlcHeader,
  1191. DlcIndicatedLength,
  1192. DataHeader,
  1193. DataTotalLength,
  1194. ReceiveContext,
  1195. FALSE,
  1196. Loopback);
  1197. //
  1198. // If the receive-continue bit is set in this frame, then we must
  1199. // reply with a RECEIVE_CONTINUE frame saying that he can continue
  1200. // sending. This old protocol option allowed a sender to send a
  1201. // single frame over to see if there was a receive posted before
  1202. // sending the entire message and potentially dropping the entire
  1203. // message. Because the TDI is indication-based, we cannot know
  1204. // if there is NO receive available until we actually try perform
  1205. // the indication, so we simply say that there is one posted.
  1206. // (This will only happen on DFMs.)
  1207. //
  1208. if (nbfHeader->Data1 & 0x01) {
  1209. //
  1210. // Save this to use in RECEIVE_CONTINUE.
  1211. //
  1212. connection->NetbiosHeader.TransmitCorrelator =
  1213. RESPONSE_CORR(nbfHeader);
  1214. NbfSendReceiveContinue (connection);
  1215. }
  1216. } else {
  1217. //
  1218. // Keep track of how many consecutive receives we have had.
  1219. //
  1220. connection->ConsecutiveReceives++;
  1221. connection->ConsecutiveSends = 0;
  1222. //
  1223. // Save this information now, it will be needed
  1224. // when the ACK for this DOL is sent.
  1225. //
  1226. connection->CurrentReceiveAckQueueable =
  1227. (nbfHeader->Data1 & DOL_OPTIONS_ACK_W_DATA_ALLOWED);
  1228. connection->CurrentReceiveNoAck =
  1229. (nbfHeader->Data1 & DOL_OPTIONS_NO_ACK);
  1230. connection->NetbiosHeader.TransmitCorrelator =
  1231. RESPONSE_CORR(nbfHeader);
  1232. //
  1233. // NOTE: This release connection->LinkSpinLock.
  1234. //
  1235. Status = ProcessIndicateData (
  1236. connection,
  1237. DlcHeader,
  1238. DlcIndicatedLength,
  1239. DataHeader,
  1240. DataTotalLength,
  1241. ReceiveContext,
  1242. TRUE,
  1243. Loopback);
  1244. }
  1245. //
  1246. // Update our "bytes received" counters.
  1247. //
  1248. Link->Provider->TempIFrameBytesReceived += DataTotalLength;
  1249. ++Link->Provider->TempIFramesReceived;
  1250. SkipProcessIndicateData:
  1251. break;
  1252. case NBF_CMD_DATA_ACK:
  1253. connection->IndicationInProgress = FALSE;
  1254. //
  1255. // This returns with the lock held.
  1256. //
  1257. CompleteSend(
  1258. connection,
  1259. TRANSMIT_CORR(nbfHeader));
  1260. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1261. Status = STATUS_SUCCESS;
  1262. break;
  1263. case NBF_CMD_SESSION_CONFIRM:
  1264. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1265. Status = ProcessSessionConfirm (
  1266. connection,
  1267. nbfHeader);
  1268. break;
  1269. case NBF_CMD_SESSION_END:
  1270. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1271. Status = ProcessSessionEnd (
  1272. connection,
  1273. nbfHeader);
  1274. break;
  1275. case NBF_CMD_SESSION_INITIALIZE:
  1276. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1277. Status = ProcessSessionInitialize (
  1278. connection,
  1279. nbfHeader);
  1280. break;
  1281. case NBF_CMD_NO_RECEIVE:
  1282. //
  1283. // This releases the connection spinlock.
  1284. //
  1285. Status = ProcessNoReceive (
  1286. connection,
  1287. nbfHeader);
  1288. break;
  1289. case NBF_CMD_RECEIVE_OUTSTANDING:
  1290. //
  1291. // This releases the connection spinlock.
  1292. //
  1293. Status = ProcessReceiveOutstanding (
  1294. connection,
  1295. nbfHeader);
  1296. break;
  1297. case NBF_CMD_RECEIVE_CONTINUE:
  1298. //
  1299. // This releases the connection spinlock.
  1300. //
  1301. Status = ProcessReceiveContinue (
  1302. connection,
  1303. nbfHeader);
  1304. break;
  1305. case NBF_CMD_SESSION_ALIVE:
  1306. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1307. Status = ProcessSessionAlive (
  1308. connection,
  1309. nbfHeader);
  1310. break;
  1311. //
  1312. // An unrecognized command was found in a NetBIOS frame. Because
  1313. // this is a connection-oriented frame, we should probably shoot
  1314. // the sender, but for now we will simply discard the packet.
  1315. //
  1316. // trash the session here-- protocol violation.
  1317. //
  1318. default:
  1319. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  1320. PANIC ("NbfProcessIIndicate: Unknown NBF command byte.\n");
  1321. connection->IndicationInProgress = FALSE;
  1322. Status = STATUS_SUCCESS;
  1323. } /* switch */
  1324. //
  1325. // A status of STATUS_MORE_PROCESSING_REQUIRED means
  1326. // that the connection reference count was inherited
  1327. // by the routine we called, so we don't do the dereference
  1328. // here.
  1329. //
  1330. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  1331. NbfDereferenceConnectionMacro("ProcessIIndicate done", connection, CREF_PROCESS_DATA);
  1332. }
  1333. //
  1334. // The N(R) in this frame acknowleges some (or all) of our packets.
  1335. // This call must come after the checkpoint acknowlegement check
  1336. // so that an RR-r/f is always sent BEFORE any new I-frames. This
  1337. // allows us to always send I-frames as commands.
  1338. // If he responded to a checkpoint, then resend all left-over
  1339. // packets.
  1340. //
  1341. // Link->NextSend = (UCHAR)(header->RcvSeq >> 1) < Link->NextSend ?
  1342. // Link->NextSend : (UCHAR)(header->RcvSeq >> 1);
  1343. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1344. if (Link->WackQ.Flink != &Link->WackQ) {
  1345. UCHAR AckSequenceNumber = (UCHAR)(header->RcvSeq >> 1);
  1346. //
  1347. // Verify that the sequence number is reasonable.
  1348. //
  1349. if (Link->NextSend >= Link->LastAckReceived) {
  1350. //
  1351. // There is no 127 -> 0 wrap between the two...
  1352. //
  1353. if ((AckSequenceNumber < Link->LastAckReceived) ||
  1354. (AckSequenceNumber > Link->NextSend)) {
  1355. goto NoResend;
  1356. }
  1357. } else {
  1358. //
  1359. // There is a 127 -> 0 wrap between the two...
  1360. //
  1361. if ((AckSequenceNumber < Link->LastAckReceived) &&
  1362. (AckSequenceNumber > Link->NextSend)) {
  1363. goto NoResend;
  1364. }
  1365. }
  1366. //
  1367. // NOTE: ResendLlcPackets may release and
  1368. // reacquire the link spinlock.
  1369. //
  1370. (VOID)ResendLlcPackets(
  1371. Link,
  1372. AckSequenceNumber,
  1373. (BOOLEAN)((!Command) && PollFinal));
  1374. NoResend:;
  1375. }
  1376. //
  1377. // Get link going again.
  1378. //
  1379. // NOTE: RestartLinkTraffic releases the link spinlock
  1380. //
  1381. RestartLinkTraffic (Link);
  1382. break;
  1383. case LINK_STATE_ADM:
  1384. //
  1385. // used to be, we'd just blow off the other guy with a DM and go home.
  1386. // it seems that OS/2 likes to believe (under some conditions) that
  1387. // it has a link up and it is still potentially active (probably
  1388. // because we return the same connection number to him that he used
  1389. // to be using). This would all be ok, except for the fact that we
  1390. // may have a connection hanging on this link waiting for a listen
  1391. // to finish. If we're in that state, go ahead and accept the
  1392. // connect.
  1393. // Set our values for link packet serial numbers to what he wants.
  1394. //
  1395. if (!IsListEmpty (&Link->ConnectionDatabase)) {
  1396. if (nbfHeader->Command == NBF_CMD_SESSION_INITIALIZE) {
  1397. //
  1398. // OK, we're at the only legal case. We've gotten an SI
  1399. // and we have a connection on this link. If the connection
  1400. // is waiting SI, we will go ahead and make believe we did
  1401. // all the correct stuff before we got it.
  1402. //
  1403. for (
  1404. p = Link->ConnectionDatabase.Flink, connection = NULL;
  1405. p != &Link->ConnectionDatabase ;
  1406. p = p->Flink, connection = NULL
  1407. ) {
  1408. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1409. if ((connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) {
  1410. // This reference is removed below
  1411. NbfReferenceConnection ("Found Listener at session init", connection, CREF_ADM_SESS);
  1412. break;
  1413. }
  1414. }
  1415. //
  1416. // Well, we've looked through the connections, if we have one,
  1417. // make it the connection of the day. Note that it will
  1418. // complete when we call ProcessSessionInitialize.
  1419. //
  1420. if (connection != NULL) {
  1421. Link->NextReceive = (UCHAR)(header->SendSeq >> 1) & (UCHAR)0x7f;
  1422. Link->NextSend = (UCHAR)(header->RcvSeq >> 1) & (UCHAR)0x7F;
  1423. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1424. NbfCompleteLink (Link); // completes the listening connection
  1425. Status = ProcessSessionInitialize (
  1426. connection,
  1427. nbfHeader);
  1428. NbfDereferenceConnection ("Processed SessInit", connection, CREF_ADM_SESS);
  1429. #if DBG
  1430. s = "ADM";
  1431. #endif
  1432. // Link is ready for use.
  1433. break;
  1434. }
  1435. }
  1436. //
  1437. // we've got a connection on a link that's in state admin.
  1438. // really bad, kill it and the link.
  1439. //
  1440. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1441. #if DBG
  1442. if (NbfDisconnectDebug) {
  1443. NbfPrint0( "NbfProcessIIndicate calling NbfStopLink\n" );
  1444. }
  1445. #endif
  1446. NbfStopLink (Link);
  1447. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1448. }
  1449. //
  1450. // We're disconnected. Tell him.
  1451. //
  1452. NbfSendDm (Link, PollFinal); // releases lock
  1453. #if DBG
  1454. s = "ADM";
  1455. #endif
  1456. break;
  1457. case LINK_STATE_CONNECTING:
  1458. //
  1459. // We've sent a SABME and are waiting for a UA. He's sent an
  1460. // I-frame too early, so just let the SABME time out.
  1461. //
  1462. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1463. #if DBG
  1464. s = "CONNECTING";
  1465. #endif
  1466. break;
  1467. case LINK_STATE_W_POLL:
  1468. //
  1469. // We're waiting for his initial poll on a RR-c/p. If he starts
  1470. // with an I-frame, then we'll let him squeak by.
  1471. //
  1472. if (!Command) {
  1473. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1474. #if DBG
  1475. s = "W_POLL";
  1476. #endif
  1477. break;
  1478. }
  1479. Link->State = LINK_STATE_READY; // we're up!
  1480. StopT1 (Link); // no longer waiting.
  1481. FakeUpdateBaseT1Timeout (Link);
  1482. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1483. NbfCompleteLink (Link); // fire up the connections.
  1484. StartTi (Link);
  1485. NbfProcessIIndicate ( // recursive, but safe
  1486. Command,
  1487. PollFinal,
  1488. Link,
  1489. DlcHeader,
  1490. DlcIndicatedLength,
  1491. DlcTotalLength,
  1492. ReceiveContext,
  1493. Loopback);
  1494. #if DBG
  1495. s = "W_POLL";
  1496. #endif
  1497. break;
  1498. case LINK_STATE_W_FINAL:
  1499. //
  1500. // We're waiting for a RR-r/f from the remote guy. I-r/f will do.
  1501. //
  1502. if (Command || !PollFinal) { // don't allow this protocol.
  1503. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1504. #if DBG
  1505. s = "W_FINAL";
  1506. #endif
  1507. break; // we sent RR-c/p.
  1508. }
  1509. Link->State = LINK_STATE_READY; // we're up.
  1510. StopT1 (Link); // no longer waiting.
  1511. StartT2 (Link); // we have an unacked I-frame.
  1512. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1513. NbfCompleteLink (Link); // fire up the connections.
  1514. StartTi (Link);
  1515. NbfProcessIIndicate ( // recursive, but safe
  1516. Command,
  1517. PollFinal,
  1518. Link,
  1519. DlcHeader,
  1520. DlcIndicatedLength,
  1521. DlcTotalLength,
  1522. ReceiveContext,
  1523. Loopback);
  1524. #if DBG
  1525. s = "W_FINAL";
  1526. #endif
  1527. break;
  1528. case LINK_STATE_W_DISC_RSP:
  1529. //
  1530. // We're waiting for a response from our DISC-c/p but instead of
  1531. // a UA-r/f, we got this I-frame. Throw the packet away.
  1532. //
  1533. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1534. #if DBG
  1535. s = "W_DISC_RSP";
  1536. #endif
  1537. break;
  1538. default:
  1539. ASSERT (FALSE);
  1540. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1541. #if DBG
  1542. s = "Unknown link state";
  1543. #endif
  1544. } /* switch */
  1545. #if DBG
  1546. IF_NBFDBG (NBF_DEBUG_DLC) {
  1547. NbfPrint1 (" NbfProcessIIndicate: (%s) I-Frame processed.\n", s);
  1548. }
  1549. #endif
  1550. return;
  1551. } /* NbfProcessIIndicate */
  1552. NTSTATUS
  1553. ProcessIndicateData(
  1554. IN PTP_CONNECTION Connection,
  1555. IN PUCHAR DlcHeader,
  1556. IN UINT DlcIndicatedLength,
  1557. IN PUCHAR DataHeader,
  1558. IN UINT DataTotalLength,
  1559. IN NDIS_HANDLE ReceiveContext,
  1560. IN BOOLEAN Last,
  1561. IN BOOLEAN Loopback
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. This routine is called to process data received in a DATA_FIRST_MIDDLE
  1566. or DATA_ONLY_LAST frame. We attempt to satisfy as many TdiReceive
  1567. requests as possible with this data.
  1568. If a receive is already active on this Connection, then we copy as much
  1569. data into the active receive's buffer as possible. If all the data is
  1570. copied and the receive request's buffer has not been filled, then the
  1571. Last flag is checked, and if it is TRUE, we go ahead and complete the
  1572. current receive with the TDI_END_OF_RECORD receive indicator. If Last
  1573. is FALSE, we simply return.
  1574. If more (uncopied) data remains in the frame, or if there is no active
  1575. receive outstanding, then an indication is issued to the owning address's
  1576. receive event handler. The event handler can take one of three actions:
  1577. 1. Return STATUS_SUCCESS, in which case the transport will assume that
  1578. all of the indicated data has been accepted by the client.
  1579. 3. Return STATUS_DATA_NOT_ACCEPTED, in which case the transport will
  1580. discard the data and set the CONNECTION_FLAGS_RECEIVE_WAKEUP bitflag
  1581. in the Connection, indicating that remaining data is to be discarded
  1582. until a receive becomes available.
  1583. NOTE: This routine is called with Connection->LinkSpinLock held,
  1584. and returns with it released. THIS ROUTINE MUST BE CALLED AT
  1585. DPC LEVEL.
  1586. Arguments:
  1587. Connection - Pointer to a TP_CONNECTION object.
  1588. DlcHeader - The pointer handed to us as the start of the NBF header by NDIS;
  1589. use this to compute the offset into the packet to start the transfer
  1590. of data to user buffers.
  1591. DlcIndicatedLength - The amount of NBF data available at indicate.
  1592. DataHeader - A pointer to the start of the data in the packet.
  1593. DataTotalLength - The total length of the packet, starting at DataHeader.
  1594. ReceiveContext - An NDIS handle that identifies the packet we are currently
  1595. processing.
  1596. Last - Boolean value that indicates whether this is the last piece of data
  1597. in a message. The DATA_ONLY_LAST processor sets this flag to TRUE when
  1598. calling this routine, and the DATA_FIRST_MIDDLE processor resets this
  1599. flag to FALSE when calling this routine.
  1600. Loopback - Is this a loopback indication; used to determine whether
  1601. to call NdisTransferData or NbfTransferLoopbackData.
  1602. Return Value:
  1603. STATUS_SUCCESS if we've consumed the packet,
  1604. --*/
  1605. {
  1606. NTSTATUS status, tmpstatus;
  1607. PDEVICE_CONTEXT deviceContext;
  1608. NDIS_STATUS ndisStatus;
  1609. PNDIS_PACKET ndisPacket;
  1610. PSINGLE_LIST_ENTRY linkage;
  1611. PIRP irp;
  1612. PIO_STACK_LOCATION irpSp;
  1613. PNDIS_BUFFER ndisBuffer;
  1614. ULONG destBytes;
  1615. ULONG bufferChainLength;
  1616. ULONG indicateBytesTransferred;
  1617. ULONG ReceiveFlags;
  1618. ULONG ndisBytesTransferred;
  1619. UINT BytesToTransfer;
  1620. ULONG bytesIndicated;
  1621. ULONG DataOffset = (ULONG)((PUCHAR)DataHeader - (PUCHAR)DlcHeader);
  1622. PRECEIVE_PACKET_TAG receiveTag;
  1623. PTP_ADDRESS_FILE addressFile;
  1624. PMDL SavedCurrentMdl;
  1625. ULONG SavedCurrentByteOffset;
  1626. BOOLEAN ActivatedLongReceive = FALSE;
  1627. BOOLEAN CompleteReceiveBool, EndOfMessage;
  1628. ULONG DumpData[2];
  1629. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1630. NbfPrint4 (" ProcessIndicateData: Entered, PacketStart: %lx Offset: %lx \n TotalLength %ld DlcIndicatedLength: %ld\n",
  1631. DlcHeader, DataOffset, DataTotalLength, DlcIndicatedLength);
  1632. }
  1633. //
  1634. // copy this packet into our receive buffer.
  1635. //
  1636. deviceContext = Connection->Provider;
  1637. if ((Connection->Flags & CONNECTION_FLAGS_RCV_CANCELLED) != 0) {
  1638. //
  1639. // A receive in progress was cancelled; we toss the data,
  1640. // but do send the DOL if it was the last piece of the
  1641. // send.
  1642. //
  1643. if (Last) {
  1644. Connection->Flags &= ~CONNECTION_FLAGS_RCV_CANCELLED;
  1645. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1646. NbfSendDataAck (Connection);
  1647. } else {
  1648. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1649. }
  1650. Connection->IndicationInProgress = FALSE;
  1651. return STATUS_SUCCESS;
  1652. }
  1653. //
  1654. // Initialize this to zero, in case we do not indicate or
  1655. // the client does not fill it in.
  1656. //
  1657. indicateBytesTransferred = 0;
  1658. if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
  1659. //
  1660. // check first to see if there is a receive available. If there is,
  1661. // use it before doing an indication.
  1662. //
  1663. if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
  1664. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1665. NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
  1666. }
  1667. //
  1668. // Found a receive, so make it the active one and
  1669. // cycle around again.
  1670. //
  1671. Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
  1672. Connection->MessageBytesReceived = 0;
  1673. Connection->MessageBytesAcked = 0;
  1674. Connection->MessageInitAccepted = 0;
  1675. Connection->CurrentReceiveIrp =
  1676. CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
  1677. IRP, Tail.Overlay.ListEntry);
  1678. Connection->CurrentReceiveSynchronous =
  1679. deviceContext->MacInfo.SingleReceive;
  1680. Connection->CurrentReceiveMdl =
  1681. Connection->CurrentReceiveIrp->MdlAddress;
  1682. Connection->ReceiveLength =
  1683. IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation (Connection->CurrentReceiveIrp));
  1684. Connection->ReceiveByteOffset = 0;
  1685. status = STATUS_SUCCESS;
  1686. goto NormalReceive;
  1687. }
  1688. //
  1689. // A receive is not active. Post a receive event.
  1690. //
  1691. if ((Connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
  1692. Connection->IndicationInProgress = FALSE;
  1693. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1694. return STATUS_SUCCESS;
  1695. }
  1696. addressFile = Connection->AddressFile;
  1697. if ((!addressFile->RegisteredReceiveHandler) ||
  1698. (Connection->ReceiveBytesUnaccepted != 0)) {
  1699. //
  1700. // There is no receive posted to the Connection, and
  1701. // no event handler. Set the RECEIVE_WAKEUP bit, so that when a
  1702. // receive does become available, it will restart the
  1703. // current send. Also send a NoReceive to tell the other
  1704. // guy he needs to resynch.
  1705. //
  1706. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1707. NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
  1708. }
  1709. Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
  1710. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1711. Connection->IndicationInProgress = FALSE;
  1712. // NbfSendNoReceive (Connection);
  1713. return STATUS_SUCCESS;
  1714. }
  1715. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1716. NbfPrint0 (" ProcessIndicateData: Receive not active. Posting event.\n");
  1717. }
  1718. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1719. LEAVE_NBF;
  1720. //
  1721. // Indicate to the user. For BytesAvailable we
  1722. // always use DataTotalLength; for BytesIndicated we use
  1723. // MIN (DlcIndicatedLength - DataOffset, DataTotalLength).
  1724. //
  1725. // To clarify BytesIndicated, on an Ethernet packet
  1726. // which is padded DataTotalLength will be shorter; on an
  1727. // Ethernet packet which is not padded and which is
  1728. // completely indicated, the two will be equal; and
  1729. // on a long Ethernet packet DlcIndicatedLength - DataOffset
  1730. // will be shorter.
  1731. //
  1732. bytesIndicated = DlcIndicatedLength - DataOffset;
  1733. if (DataTotalLength <= bytesIndicated) {
  1734. bytesIndicated = DataTotalLength;
  1735. }
  1736. ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
  1737. if (Last) {
  1738. ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
  1739. }
  1740. if (deviceContext->MacInfo.CopyLookahead) {
  1741. ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
  1742. }
  1743. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1744. NbfPrint2("ProcessIndicateData: Indicating - Bytes Indi =%lx, DataTotalLen =%lx.\n",
  1745. bytesIndicated, DataTotalLength);
  1746. }
  1747. status = (*addressFile->ReceiveHandler)(
  1748. addressFile->ReceiveHandlerContext,
  1749. Connection->Context,
  1750. ReceiveFlags,
  1751. bytesIndicated,
  1752. DataTotalLength, // BytesAvailable
  1753. &indicateBytesTransferred,
  1754. DataHeader,
  1755. &irp);
  1756. #if PKT_LOG
  1757. // We indicated here, log packet indicated for debugging
  1758. NbfLogIndPacket(Connection,
  1759. DataHeader,
  1760. DataTotalLength,
  1761. bytesIndicated,
  1762. indicateBytesTransferred,
  1763. status);
  1764. #endif
  1765. ENTER_NBF;
  1766. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1767. ULONG SpecialIrpLength;
  1768. PTDI_REQUEST_KERNEL_RECEIVE Parameters;
  1769. //
  1770. // The client's event handler has returned an IRP in the
  1771. // form of a TdiReceive that is to be associated with this
  1772. // data. The request will be installed at the front of the
  1773. // ReceiveQueue, and then made the active receive request.
  1774. // This request will be used to accept the incoming data, which
  1775. // will happen below.
  1776. //
  1777. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1778. NbfPrint0 (" ProcessIndicateData: Status=STATUS_MORE_PROCESSING_REQUIRED.\n");
  1779. NbfPrint4 (" ProcessIndicateData: Irp=%lx, Mdl=%lx, UserBuffer=%lx, Count=%ld.\n",
  1780. irp, irp->MdlAddress, irp->UserBuffer,
  1781. MmGetMdlByteCount (irp->MdlAddress));
  1782. }
  1783. //
  1784. // Queueing a receive of any kind causes a Connection reference;
  1785. // that's what we've just done here, so make the Connection stick
  1786. // around. We create a request to keep a packets outstanding ref
  1787. // count for the current IRP; we queue this on the connection's
  1788. // receive queue so we can treat it like a normal receive. If
  1789. // we can't get a request to describe this irp, we can't keep it
  1790. // around hoping for better later; we simple fail it with
  1791. // insufficient resources. Note this is only likely to happen if
  1792. // we've completely run out of transport memory.
  1793. //
  1794. irp->IoStatus.Information = 0; // byte transfer count.
  1795. irp->IoStatus.Status = STATUS_PENDING;
  1796. irpSp = IoGetCurrentIrpStackLocation (irp);
  1797. ASSERT (irpSp->FileObject->FsContext == Connection);
  1798. Parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  1799. SpecialIrpLength = Parameters->ReceiveLength;
  1800. //
  1801. // If the packet is a DOL, and it will fit entirely
  1802. // inside this posted IRP, then we don't bother
  1803. // creating a request, because we don't need any of
  1804. // that overhead. We also don't set ReceiveBytes
  1805. // Unaccepted, since this receive would clear it
  1806. // anyway.
  1807. //
  1808. if (Last &&
  1809. (SpecialIrpLength >= (DataTotalLength - indicateBytesTransferred))) {
  1810. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1811. Connection->SpecialReceiveIrp = irp;
  1812. Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
  1813. Connection->ReceiveLength = SpecialIrpLength;
  1814. Connection->MessageBytesReceived = 0;
  1815. Connection->MessageInitAccepted = indicateBytesTransferred;
  1816. Connection->MessageBytesAcked = 0;
  1817. Connection->CurrentReceiveIrp = NULL;
  1818. Connection->CurrentReceiveSynchronous = TRUE;
  1819. Connection->CurrentReceiveMdl = irp->MdlAddress;
  1820. Connection->ReceiveByteOffset = 0;
  1821. if ((Parameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0) {
  1822. Connection->CurrentReceiveAckQueueable = FALSE;
  1823. }
  1824. #if DBG
  1825. //
  1826. // switch our reference from PROCESS_DATA to
  1827. // RECEIVE_IRP, this is OK because the RECEIVE_IRP
  1828. // reference won't be removed until Transfer
  1829. // DataComplete, which is the last thing
  1830. // we call.
  1831. //
  1832. NbfReferenceConnection("Special IRP", Connection, CREF_RECEIVE_IRP);
  1833. NbfDereferenceConnection("ProcessIIndicate done", Connection, CREF_PROCESS_DATA);
  1834. #endif
  1835. } else {
  1836. KIRQL cancelIrql;
  1837. //
  1838. // The normal path, for longer receives.
  1839. //
  1840. IoAcquireCancelSpinLock(&cancelIrql);
  1841. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1842. IRP_RECEIVE_IRP(irpSp) = irp;
  1843. if (deviceContext->MacInfo.SingleReceive) {
  1844. IRP_RECEIVE_REFCOUNT(irpSp) = 1;
  1845. } else {
  1846. #if DBG
  1847. IRP_RECEIVE_REFCOUNT(irpSp) = 1;
  1848. NbfReferenceReceiveIrpLocked ("Transfer Data", irpSp, RREF_RECEIVE);
  1849. #else
  1850. IRP_RECEIVE_REFCOUNT(irpSp) = 2; // include one for first xfer
  1851. #endif
  1852. }
  1853. //
  1854. // If the Connection is stopping, abort this request.
  1855. //
  1856. if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
  1857. Connection->IndicationInProgress = FALSE;
  1858. NbfReferenceConnection("Special IRP stopping", Connection, CREF_RECEIVE_IRP);
  1859. NbfCompleteReceiveIrp (
  1860. irp,
  1861. Connection->Status,
  1862. 0);
  1863. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1864. IoReleaseCancelSpinLock(cancelIrql);
  1865. if (!deviceContext->MacInfo.SingleReceive) {
  1866. NbfDereferenceReceiveIrp ("Not ready", irpSp, RREF_RECEIVE);
  1867. }
  1868. return STATUS_SUCCESS; // we have consumed the packet
  1869. }
  1870. //
  1871. // If this IRP has been cancelled, complete it now.
  1872. //
  1873. if (irp->Cancel) {
  1874. Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
  1875. Connection->IndicationInProgress = FALSE;
  1876. NbfReferenceConnection("Special IRP cancelled", Connection, CREF_RECEIVE_IRP);
  1877. //
  1878. // It is safe to call this with locks held.
  1879. //
  1880. NbfCompleteReceiveIrp (irp, STATUS_CANCELLED, 0);
  1881. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1882. IoReleaseCancelSpinLock(cancelIrql);
  1883. if (!deviceContext->MacInfo.SingleReceive) {
  1884. NbfDereferenceReceiveIrp ("Cancelled", irpSp, RREF_RECEIVE);
  1885. }
  1886. return STATUS_SUCCESS;
  1887. }
  1888. //
  1889. // Insert the request on the head of the connection's
  1890. // receive queue, so it can be handled like a normal
  1891. // receive.
  1892. //
  1893. InsertHeadList (&Connection->ReceiveQueue, &irp->Tail.Overlay.ListEntry);
  1894. IoSetCancelRoutine(irp, NbfCancelReceive);
  1895. //
  1896. // Release the cancel spinlock out of order. Since we were
  1897. // at DPC level when we acquired it, we don't have to fiddle
  1898. // with swapping irqls.
  1899. //
  1900. ASSERT(cancelIrql == DISPATCH_LEVEL);
  1901. IoReleaseCancelSpinLock(cancelIrql);
  1902. Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
  1903. Connection->ReceiveLength = Parameters->ReceiveLength;
  1904. Connection->MessageBytesReceived = 0;
  1905. Connection->MessageInitAccepted = indicateBytesTransferred;
  1906. Connection->ReceiveBytesUnaccepted = DataTotalLength - indicateBytesTransferred;
  1907. Connection->MessageBytesAcked = 0;
  1908. Connection->CurrentReceiveIrp = irp;
  1909. Connection->CurrentReceiveSynchronous =
  1910. deviceContext->MacInfo.SingleReceive;
  1911. Connection->CurrentReceiveMdl = irp->MdlAddress;
  1912. Connection->ReceiveByteOffset = 0;
  1913. #if DBG
  1914. //
  1915. // switch our reference from PROCESS_DATA to
  1916. // REQUEST, this is OK because the REQUEST
  1917. // reference won't be removed until Transfer
  1918. // DataComplete, which is the last thing
  1919. // we call.
  1920. //
  1921. NbfReferenceConnection("Special IRP", Connection, CREF_RECEIVE_IRP);
  1922. NbfDereferenceConnection("ProcessIIndicate done", Connection, CREF_PROCESS_DATA);
  1923. #endif
  1924. //
  1925. // Make a note so we know what to do below.
  1926. //
  1927. ActivatedLongReceive = TRUE;
  1928. #if DBG
  1929. NbfReceives[NbfReceivesNext].Irp = irp;
  1930. NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
  1931. #endif
  1932. }
  1933. } else if (status == STATUS_SUCCESS) {
  1934. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1935. NbfPrint0 (" ProcessIndicateData: Status=STATUS_SUCCESS.\n");
  1936. }
  1937. //
  1938. // The client has accepted some or all of the indicated data in
  1939. // the event handler. Update MessageBytesReceived variable in
  1940. // the Connection so that if we are called upon to ACK him
  1941. // at the byte level, then we can correctly report the
  1942. // number of bytes received thus far. If this is a DOL,
  1943. // then reset the number of bytes received, since this value
  1944. // always at zero for new messages. If the data indicated wasn't
  1945. // all the data in this packet, flow control to the sender that
  1946. // didn't get all of the data.
  1947. //
  1948. if (Last && (indicateBytesTransferred >= DataTotalLength)) {
  1949. ASSERT (indicateBytesTransferred == DataTotalLength);
  1950. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1951. //
  1952. // This will send a DATA ACK or queue a request for
  1953. // a piggyback ack.
  1954. //
  1955. // NOTE: It will also release the connection spinlock.
  1956. //
  1957. Connection->MessageBytesReceived = 0;
  1958. Connection->MessageInitAccepted = indicateBytesTransferred;
  1959. NbfAcknowledgeDataOnlyLast(
  1960. Connection,
  1961. Connection->MessageBytesReceived
  1962. );
  1963. Connection->IndicationInProgress = FALSE;
  1964. return STATUS_SUCCESS;
  1965. } else {
  1966. //
  1967. // This gets gory.
  1968. // If this packet wasn't a DOL, we have no way of knowing how
  1969. // much the client will take of the data in this send that is
  1970. // now arriving. Pathological clients will break this protocol
  1971. // if they do things like taking part of the receive at indicate
  1972. // immediate and then return an irp (this would make the byte
  1973. // count wrong for the irp).
  1974. //
  1975. // Since the client did not take all the data that we
  1976. // told him about, he will eventually post a receive.
  1977. // If this has not already happened then we set the
  1978. // RECEIVE_WAKEUP bit and send a NO_RECEIVE.
  1979. //
  1980. #if DBG
  1981. NbfPrint0("NBF: Indicate returned SUCCESS but did not take all data\n");
  1982. #endif
  1983. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1984. Connection->MessageBytesReceived = 0;
  1985. Connection->MessageInitAccepted = indicateBytesTransferred;
  1986. Connection->ReceiveBytesUnaccepted = DataTotalLength - indicateBytesTransferred;
  1987. Connection->MessageBytesAcked = 0;
  1988. if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
  1989. //
  1990. // There is no receive posted to the Connection.
  1991. //
  1992. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  1993. NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
  1994. }
  1995. if (indicateBytesTransferred == DataTotalLength) {
  1996. //
  1997. // This means he took everything, but it was not
  1998. // a DOL; there is no need to do anything since
  1999. // the rest of the data will be right behind.
  2000. //
  2001. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2002. } else {
  2003. Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
  2004. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2005. NbfSendNoReceive (Connection);
  2006. }
  2007. Connection->IndicationInProgress = FALSE;
  2008. return STATUS_SUCCESS;
  2009. } else {
  2010. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  2011. NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
  2012. }
  2013. //
  2014. // Found a receive, so make it the active one. This will cause
  2015. // an NdisTransferData below, so we don't dereference the
  2016. // Connection here.
  2017. //
  2018. Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
  2019. Connection->CurrentReceiveIrp =
  2020. CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
  2021. IRP, Tail.Overlay.ListEntry);
  2022. Connection->CurrentReceiveSynchronous =
  2023. deviceContext->MacInfo.SingleReceive;
  2024. Connection->CurrentReceiveMdl =
  2025. Connection->CurrentReceiveIrp->MdlAddress;
  2026. Connection->ReceiveLength =
  2027. IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp));
  2028. Connection->ReceiveByteOffset = 0;
  2029. }
  2030. }
  2031. } else { // STATUS_DATA_NOT_ACCEPTED or other
  2032. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  2033. NbfPrint0 (" ProcessIndicateData: Status=STATUS_DATA_NOT_ACCEPTED.\n");
  2034. }
  2035. //
  2036. // Either there is no event handler installed (the default
  2037. // handler returns this code) or the event handler is not
  2038. // able to process the received data at this time. If there
  2039. // is a TdiReceive request outstanding on this Connection's
  2040. // ReceiveQueue, then we may use it to receive this data.
  2041. // If there is no request outstanding, then we must initiate
  2042. // flow control at the transport level.
  2043. //
  2044. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2045. Connection->ReceiveBytesUnaccepted = DataTotalLength;
  2046. if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
  2047. //
  2048. // There is no receive posted to the Connection, and
  2049. // the event handler didn't want to accept the incoming
  2050. // data. Set the RECEIVE_WAKEUP bit, so that when a
  2051. // receive does become available, it will restart the
  2052. // current send. Also send a NoReceive to tell the other
  2053. // guy he needs to resynch.
  2054. //
  2055. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  2056. NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
  2057. }
  2058. Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
  2059. Connection->IndicationInProgress = FALSE;
  2060. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2061. return STATUS_SUCCESS;
  2062. } else {
  2063. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  2064. NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
  2065. }
  2066. //
  2067. // Found a receive, so make it the active one. This will cause
  2068. // an NdisTransferData below, so we don't dereference the
  2069. // Connection here.
  2070. //
  2071. Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
  2072. Connection->MessageBytesReceived = 0;
  2073. Connection->MessageBytesAcked = 0;
  2074. Connection->MessageInitAccepted = 0;
  2075. Connection->CurrentReceiveIrp =
  2076. CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
  2077. IRP, Tail.Overlay.ListEntry);
  2078. Connection->CurrentReceiveSynchronous =
  2079. deviceContext->MacInfo.SingleReceive;
  2080. Connection->CurrentReceiveMdl =
  2081. Connection->CurrentReceiveIrp->MdlAddress;
  2082. Connection->ReceiveLength =
  2083. IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp));
  2084. Connection->ReceiveByteOffset = 0;
  2085. }
  2086. }
  2087. } else {
  2088. //
  2089. // A receive is active, set the status to show
  2090. // that so far.
  2091. //
  2092. status = STATUS_SUCCESS;
  2093. }
  2094. NormalReceive:;
  2095. //
  2096. // NOTE: The connection spinlock is held here.
  2097. //
  2098. // We should only get through here if a receive is active
  2099. // and we have not released the lock since checking or
  2100. // making one active.
  2101. //
  2102. ASSERT(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE);
  2103. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  2104. NbfPrint2 (" ProcessIndicateData: Receive is active. ReceiveLengthLength: %ld Offset: %ld.\n",
  2105. Connection->ReceiveLength, Connection->MessageBytesReceived);
  2106. }
  2107. destBytes = Connection->ReceiveLength - Connection->MessageBytesReceived;
  2108. //
  2109. // If we just activated a non-special receive IRP, we already
  2110. // added a refcount for this transfer.
  2111. //
  2112. if (!Connection->CurrentReceiveSynchronous && !ActivatedLongReceive) {
  2113. NbfReferenceReceiveIrpLocked ("Transfer Data", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
  2114. }
  2115. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2116. //
  2117. // Determine how much data remains to be transferred.
  2118. //
  2119. ASSERT (indicateBytesTransferred <= DataTotalLength);
  2120. BytesToTransfer = DataTotalLength - indicateBytesTransferred;
  2121. if (destBytes < BytesToTransfer) {
  2122. //
  2123. // If the data overflows the current receive, then make a
  2124. // note that we should complete the receive at the end of
  2125. // transfer data, but with EOR false.
  2126. //
  2127. EndOfMessage = FALSE;
  2128. CompleteReceiveBool = TRUE;
  2129. BytesToTransfer = destBytes;
  2130. } else if (destBytes == BytesToTransfer) {
  2131. //
  2132. // If the data just fills the current receive, then complete
  2133. // the receive; EOR depends on whether this is a DOL or not.
  2134. //
  2135. EndOfMessage = Last;
  2136. CompleteReceiveBool = TRUE;
  2137. } else {
  2138. //
  2139. // Complete the receive if this is a DOL.
  2140. //
  2141. EndOfMessage = Last;
  2142. CompleteReceiveBool = Last;
  2143. }
  2144. //
  2145. // If we can copy the data directly, then do so.
  2146. //
  2147. if ((BytesToTransfer > 0) &&
  2148. (DataOffset + indicateBytesTransferred + BytesToTransfer <= DlcIndicatedLength)) {
  2149. //
  2150. // All the data that we need to transfer is available in
  2151. // the indication, so copy it directly.
  2152. //
  2153. ULONG BytesNow, BytesLeft;
  2154. PUCHAR CurTarget, CurSource;
  2155. ULONG CurTargetLen;
  2156. PMDL CurMdl;
  2157. ULONG CurByteOffset;
  2158. //
  2159. // First we advance the connection pointers by the appropriate
  2160. // number of bytes, so that we can reallow indications (only
  2161. // do this if needed).
  2162. //
  2163. CurMdl = Connection->CurrentReceiveMdl;
  2164. CurByteOffset = Connection->ReceiveByteOffset;
  2165. if (!deviceContext->MacInfo.ReceiveSerialized) {
  2166. SavedCurrentMdl = CurMdl;
  2167. SavedCurrentByteOffset = CurByteOffset;
  2168. BytesLeft = BytesToTransfer;
  2169. CurTargetLen = MmGetMdlByteCount (CurMdl) - CurByteOffset;
  2170. while (TRUE) {
  2171. if (BytesLeft >= CurTargetLen) {
  2172. BytesLeft -= CurTargetLen;
  2173. CurMdl = CurMdl->Next;
  2174. CurByteOffset = 0;
  2175. if (BytesLeft == 0) {
  2176. break;
  2177. }
  2178. CurTargetLen = MmGetMdlByteCount (CurMdl);
  2179. } else {
  2180. CurByteOffset += BytesLeft;
  2181. break;
  2182. }
  2183. }
  2184. Connection->CurrentReceiveMdl = CurMdl;
  2185. Connection->ReceiveByteOffset = CurByteOffset;
  2186. Connection->MessageBytesReceived += BytesToTransfer;
  2187. //
  2188. // Set this up, we know the transfer won't
  2189. // "fail" but another one at the same time
  2190. // might.
  2191. //
  2192. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2193. if (Connection->TransferBytesPending == 0) {
  2194. Connection->TransferBytesPending = BytesToTransfer;
  2195. Connection->TotalTransferBytesPending = BytesToTransfer;
  2196. Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
  2197. Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
  2198. } else {
  2199. Connection->TransferBytesPending += BytesToTransfer;
  2200. Connection->TotalTransferBytesPending += BytesToTransfer;
  2201. }
  2202. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2203. Connection->IndicationInProgress = FALSE;
  2204. //
  2205. // Restore these for the next section of code.
  2206. //
  2207. CurMdl = SavedCurrentMdl;
  2208. CurByteOffset = SavedCurrentByteOffset;
  2209. }
  2210. CurTarget = (PUCHAR)(MmGetSystemAddressForMdl(CurMdl)) + CurByteOffset;
  2211. CurTargetLen = MmGetMdlByteCount(CurMdl) - CurByteOffset;
  2212. CurSource = DataHeader + indicateBytesTransferred;
  2213. BytesLeft = BytesToTransfer;
  2214. while (TRUE) {
  2215. if (CurTargetLen < BytesLeft) {
  2216. BytesNow = CurTargetLen;
  2217. } else {
  2218. BytesNow = BytesLeft;
  2219. }
  2220. TdiCopyLookaheadData(
  2221. CurTarget,
  2222. CurSource,
  2223. BytesNow,
  2224. deviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
  2225. if (BytesNow == CurTargetLen) {
  2226. BytesLeft -= BytesNow;
  2227. CurMdl = CurMdl->Next;
  2228. CurByteOffset = 0;
  2229. if (BytesLeft > 0) {
  2230. CurTarget = MmGetSystemAddressForMdl(CurMdl);
  2231. CurTargetLen = MmGetMdlByteCount(CurMdl);
  2232. CurSource += BytesNow;
  2233. } else {
  2234. break;
  2235. }
  2236. } else {
  2237. CurByteOffset += BytesNow;
  2238. ASSERT (BytesLeft == BytesNow);
  2239. break;
  2240. }
  2241. }
  2242. if (deviceContext->MacInfo.ReceiveSerialized) {
  2243. //
  2244. // If we delayed updating these, do it now.
  2245. //
  2246. Connection->CurrentReceiveMdl = CurMdl;
  2247. Connection->ReceiveByteOffset = CurByteOffset;
  2248. Connection->MessageBytesReceived += BytesToTransfer;
  2249. Connection->IndicationInProgress = FALSE;
  2250. } else {
  2251. //
  2252. // Check if something else failed and we are the
  2253. // last to complete, if so then back up our
  2254. // receive pointers and send a receive
  2255. // outstanding to make him resend.
  2256. //
  2257. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2258. Connection->TransferBytesPending -= BytesToTransfer;
  2259. if ((Connection->TransferBytesPending == 0) &&
  2260. (Connection->Flags & CONNECTION_FLAGS_TRANSFER_FAIL)) {
  2261. Connection->CurrentReceiveMdl = Connection->SavedCurrentReceiveMdl;
  2262. Connection->ReceiveByteOffset = Connection->SavedReceiveByteOffset;
  2263. Connection->MessageBytesReceived -= Connection->TotalTransferBytesPending;
  2264. Connection->Flags &= ~CONNECTION_FLAGS_TRANSFER_FAIL;
  2265. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2266. NbfSendReceiveOutstanding (Connection);
  2267. if (!Connection->SpecialReceiveIrp &&
  2268. !Connection->CurrentReceiveSynchronous) {
  2269. NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
  2270. }
  2271. return status;
  2272. } else {
  2273. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2274. }
  2275. }
  2276. //
  2277. // Now that the transfer is complete, simulate a call to
  2278. // TransferDataComplete.
  2279. //
  2280. if (!Connection->SpecialReceiveIrp) {
  2281. Connection->CurrentReceiveIrp->IoStatus.Information += BytesToTransfer;
  2282. if (!Connection->CurrentReceiveSynchronous) {
  2283. NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
  2284. }
  2285. }
  2286. //
  2287. // see if we've completed the current receive. If so, move to the next one.
  2288. //
  2289. if (CompleteReceiveBool) {
  2290. CompleteReceive (Connection, EndOfMessage, BytesToTransfer);
  2291. }
  2292. return status;
  2293. }
  2294. //
  2295. // Get a packet for the coming transfer
  2296. //
  2297. linkage = ExInterlockedPopEntryList(
  2298. &deviceContext->ReceivePacketPool,
  2299. &deviceContext->Interlock);
  2300. if (linkage != NULL) {
  2301. ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
  2302. } else {
  2303. deviceContext->ReceivePacketExhausted++;
  2304. if (!Connection->CurrentReceiveSynchronous) {
  2305. NbfDereferenceReceiveIrp ("No receive packet", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
  2306. }
  2307. //
  2308. // We could not get a receive packet. We do have an active
  2309. // receive, so we just send a receive outstanding to
  2310. // get him to resend. Hopefully we will have a receive
  2311. // packet available when the data is resent.
  2312. //
  2313. if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
  2314. NbfSendNoReceive (Connection);
  2315. }
  2316. NbfSendReceiveOutstanding (Connection);
  2317. #if DBG
  2318. NbfPrint0 (" ProcessIndicateData: Discarding Packet, no receive packets\n");
  2319. #endif
  2320. Connection->IndicationInProgress = FALSE;
  2321. return status;
  2322. }
  2323. //
  2324. // Initialize the receive packet.
  2325. //
  2326. receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
  2327. // receiveTag->PacketType = TYPE_AT_INDICATE;
  2328. receiveTag->Connection = Connection;
  2329. receiveTag->TransferDataPended = TRUE;
  2330. receiveTag->EndOfMessage = EndOfMessage;
  2331. receiveTag->CompleteReceive = CompleteReceiveBool;
  2332. //
  2333. // if we've got zero bytes left, avoid the TransferData below and
  2334. // just deliver.
  2335. //
  2336. if (BytesToTransfer <= 0) {
  2337. Connection->IndicationInProgress = FALSE;
  2338. receiveTag->TransferDataPended = FALSE;
  2339. receiveTag->AllocatedNdisBuffer = FALSE;
  2340. receiveTag->BytesToTransfer = 0;
  2341. NbfTransferDataComplete (
  2342. deviceContext,
  2343. ndisPacket,
  2344. NDIS_STATUS_SUCCESS,
  2345. 0);
  2346. return status;
  2347. }
  2348. //
  2349. // describe the right part of the user buffer to NDIS. If we can't get
  2350. // the mdl for the packet, drop dead. Bump the request reference count
  2351. // so that we know we need to hold open receives until the NDIS transfer
  2352. // data requests complete.
  2353. //
  2354. SavedCurrentMdl = Connection->CurrentReceiveMdl;
  2355. SavedCurrentByteOffset = Connection->ReceiveByteOffset;
  2356. if ((Connection->ReceiveByteOffset == 0) &&
  2357. (CompleteReceiveBool)) {
  2358. //
  2359. // If we are transferring into the beginning of
  2360. // the current MDL, and we will be completing the
  2361. // receive after the transfer, then we don't need to
  2362. // copy it.
  2363. //
  2364. ndisBuffer = (PNDIS_BUFFER)Connection->CurrentReceiveMdl;
  2365. bufferChainLength = BytesToTransfer;
  2366. Connection->CurrentReceiveMdl = NULL;
  2367. // Connection->ReceiveByteOffset = 0;
  2368. receiveTag->AllocatedNdisBuffer = FALSE;
  2369. tmpstatus = STATUS_SUCCESS;
  2370. } else {
  2371. tmpstatus = BuildBufferChainFromMdlChain (
  2372. deviceContext,
  2373. Connection->CurrentReceiveMdl,
  2374. Connection->ReceiveByteOffset,
  2375. BytesToTransfer,
  2376. &ndisBuffer,
  2377. &Connection->CurrentReceiveMdl,
  2378. &Connection->ReceiveByteOffset,
  2379. &bufferChainLength);
  2380. receiveTag->AllocatedNdisBuffer = TRUE;
  2381. }
  2382. if ((!NT_SUCCESS (tmpstatus)) || (bufferChainLength != BytesToTransfer)) {
  2383. DumpData[0] = bufferChainLength;
  2384. DumpData[1] = BytesToTransfer;
  2385. NbfWriteGeneralErrorLog(
  2386. deviceContext,
  2387. EVENT_TRANSPORT_TRANSFER_DATA,
  2388. 604,
  2389. tmpstatus,
  2390. NULL,
  2391. 2,
  2392. DumpData);
  2393. if (!Connection->CurrentReceiveSynchronous) {
  2394. NbfDereferenceReceiveIrp ("No MDL chain", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
  2395. }
  2396. //
  2397. // Restore our old state and make him resend.
  2398. //
  2399. Connection->CurrentReceiveMdl = SavedCurrentMdl;
  2400. Connection->ReceiveByteOffset = SavedCurrentByteOffset;
  2401. if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
  2402. NbfSendNoReceive (Connection);
  2403. }
  2404. NbfSendReceiveOutstanding (Connection);
  2405. Connection->IndicationInProgress = FALSE;
  2406. ExInterlockedPushEntryList(
  2407. &deviceContext->ReceivePacketPool,
  2408. &receiveTag->Linkage,
  2409. &deviceContext->Interlock);
  2410. return status;
  2411. }
  2412. IF_NBFDBG (NBF_DEBUG_DLC) {
  2413. NbfPrint3 (" ProcessIndicateData: Mdl: %lx user buffer: %lx user offset: %lx \n",
  2414. ndisBuffer, Connection->CurrentReceiveMdl, Connection->ReceiveByteOffset);
  2415. }
  2416. NdisChainBufferAtFront (ndisPacket, ndisBuffer);
  2417. IF_NBFDBG (NBF_DEBUG_DLC) {
  2418. NbfPrint1 (" ProcessIndicateData: Transferring Complete Packet: %lx\n",
  2419. ndisPacket);
  2420. }
  2421. //
  2422. // update the number of bytes received; OK to do this
  2423. // unprotected since IndicationInProgress is still FALSE.
  2424. //
  2425. //
  2426. Connection->MessageBytesReceived += BytesToTransfer;
  2427. //
  2428. // We have to do this for two reasons: for MACs that
  2429. // are not receive-serialized, to keep track of it,
  2430. // and for MACs where transfer data can pend, so
  2431. // we have stuff saved to handle failure later (if
  2432. // the MAC is synchronous on transfers and it fails,
  2433. // we fill these fields in before calling CompleteTransferData).
  2434. //
  2435. if (!deviceContext->MacInfo.SingleReceive) {
  2436. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2437. receiveTag->BytesToTransfer = BytesToTransfer;
  2438. if (Connection->TransferBytesPending == 0) {
  2439. Connection->TransferBytesPending = BytesToTransfer;
  2440. Connection->TotalTransferBytesPending = BytesToTransfer;
  2441. Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
  2442. Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
  2443. } else {
  2444. Connection->TransferBytesPending += BytesToTransfer;
  2445. Connection->TotalTransferBytesPending += BytesToTransfer;
  2446. }
  2447. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2448. }
  2449. //
  2450. // We have now updated all the connection counters (
  2451. // assuming the TransferData will succeed) and this
  2452. // packet's location in the request is secured, so we
  2453. // can be reentered.
  2454. //
  2455. Connection->IndicationInProgress = FALSE;
  2456. if (Loopback) {
  2457. NbfTransferLoopbackData(
  2458. &ndisStatus,
  2459. deviceContext,
  2460. ReceiveContext,
  2461. deviceContext->MacInfo.TransferDataOffset +
  2462. DataOffset + indicateBytesTransferred,
  2463. BytesToTransfer,
  2464. ndisPacket,
  2465. (PUINT)&ndisBytesTransferred
  2466. );
  2467. } else {
  2468. if (deviceContext->NdisBindingHandle) {
  2469. NdisTransferData (
  2470. &ndisStatus,
  2471. deviceContext->NdisBindingHandle,
  2472. ReceiveContext,
  2473. deviceContext->MacInfo.TransferDataOffset +
  2474. DataOffset + indicateBytesTransferred,
  2475. BytesToTransfer,
  2476. ndisPacket,
  2477. (PUINT)&ndisBytesTransferred);
  2478. }
  2479. else {
  2480. ndisStatus = STATUS_INVALID_DEVICE_STATE;
  2481. }
  2482. }
  2483. //
  2484. // handle the various completion codes
  2485. //
  2486. if ((ndisStatus == NDIS_STATUS_SUCCESS) &&
  2487. (ndisBytesTransferred == BytesToTransfer)) {
  2488. //
  2489. // deallocate the buffers and such that we've used if at indicate
  2490. //
  2491. receiveTag->TransferDataPended = FALSE;
  2492. NbfTransferDataComplete (
  2493. deviceContext,
  2494. ndisPacket,
  2495. ndisStatus,
  2496. BytesToTransfer);
  2497. } else if (ndisStatus == NDIS_STATUS_PENDING) {
  2498. //
  2499. // Because TransferDataPended stays TRUE, this reference will
  2500. // be removed in TransferDataComplete. It is OK to do this
  2501. // now, even though TransferDataComplete may already have been
  2502. // called, because we also hold the ProcessIIndicate reference
  2503. // so there will be no "bounce".
  2504. //
  2505. NbfReferenceConnection ("TransferData pended", Connection, CREF_TRANSFER_DATA);
  2506. } else {
  2507. //
  2508. // something broke; certainly we'll never get NdisTransferData
  2509. // asynch completion with this error status. We set things up
  2510. // to that NbfTransferDataComplete will do the right thing.
  2511. //
  2512. if (deviceContext->MacInfo.SingleReceive) {
  2513. Connection->TransferBytesPending = BytesToTransfer;
  2514. Connection->TotalTransferBytesPending = BytesToTransfer;
  2515. Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
  2516. Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
  2517. receiveTag->BytesToTransfer = BytesToTransfer;
  2518. }
  2519. receiveTag->TransferDataPended = FALSE;
  2520. NbfTransferDataComplete (
  2521. deviceContext,
  2522. ndisPacket,
  2523. ndisStatus,
  2524. BytesToTransfer);
  2525. }
  2526. return status; // which only means we've dealt with the packet
  2527. } /* ProcessIndicateData */