Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2465 lines
88 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. session.c
  5. Abstract:
  6. This module contains the code to handle session frames
  7. for the Netbios module of the ISN transport.
  8. Author:
  9. Adam Barr (adamba) 28-November-1993
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #ifdef RASAUTODIAL
  16. #include <acd.h>
  17. #include <acdapi.h>
  18. #endif // RASAUTODIAL
  19. #pragma hdrstop
  20. #ifdef RASAUTODIAL
  21. extern BOOLEAN fAcdLoadedG;
  22. extern ACD_DRIVER AcdDriverG;
  23. VOID
  24. NbiNoteNewConnection(
  25. PCONNECTION pConnection
  26. );
  27. #endif
  28. #ifdef RSRC_TIMEOUT_DBG
  29. VOID
  30. NbiSendDeathPacket(
  31. IN PCONNECTION Connection,
  32. IN CTELockHandle LockHandle
  33. )
  34. {
  35. PNDIS_PACKET Packet = PACKET(&NbiGlobalDeathPacket);
  36. PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
  37. NB_CONNECTION UNALIGNED * Header;
  38. PDEVICE Device = NbiDevice;
  39. NDIS_STATUS NdisStatus;
  40. if ( Reserved->SendInProgress ) {
  41. DbgPrint("***Could not send death packet - in use\n");
  42. NB_FREE_LOCK(&Connection->Lock, LockHandle);
  43. return;
  44. }
  45. Reserved->SendInProgress = TRUE;
  46. Reserved->Type = SEND_TYPE_DEATH_PACKET;
  47. //
  48. // Fill in the IPX header -- the default header has the broadcast
  49. // address on net 0 as the destination IPX address.
  50. //
  51. Header = (NB_CONNECTION UNALIGNED *)
  52. (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  53. RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
  54. Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
  55. Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
  56. Header->IpxHeader.PacketType = 0x04;
  57. //
  58. // Now fill in the Netbios header.
  59. //
  60. Header->Session.ConnectionControlFlag = 0;
  61. Header->Session.DataStreamType = NB_CMD_DEATH_PACKET;
  62. Header->Session.SourceConnectionId = Connection->LocalConnectionId;
  63. Header->Session.DestConnectionId = Connection->RemoteConnectionId;
  64. Header->Session.SendSequence = 0;
  65. Header->Session.TotalDataLength = 0;
  66. Header->Session.Offset = 0;
  67. Header->Session.DataLength = 0;
  68. NB_FREE_LOCK(&Connection->Lock, LockHandle);
  69. DbgPrint("*****Death packet is being sent for connection %lx, to <%.16s>\n",Connection, Connection->RemoteName);
  70. //
  71. // Now send the frame, IPX will adjust the length of the
  72. // first buffer correctly.
  73. //
  74. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
  75. if ((NdisStatus =
  76. (*Device->Bind.SendHandler)(
  77. &Connection->LocalTarget,
  78. Packet,
  79. sizeof(NB_CONNECTION),
  80. sizeof(NB_CONNECTION))) != STATUS_PENDING) {
  81. NbiSendComplete(
  82. Packet,
  83. NdisStatus);
  84. }
  85. }
  86. #endif //RSRC_TIMEOUT_DBG
  87. VOID
  88. NbiProcessSessionData(
  89. IN NDIS_HANDLE MacBindingHandle,
  90. IN NDIS_HANDLE MacReceiveContext,
  91. IN PIPX_LOCAL_TARGET RemoteAddress,
  92. IN ULONG MacOptions,
  93. IN PUCHAR LookaheadBuffer,
  94. IN UINT LookaheadBufferSize,
  95. IN UINT LookaheadBufferOffset,
  96. IN UINT PacketSize
  97. )
  98. /*++
  99. Routine Description:
  100. This routine handles NB_CMD_SESSION_DATA frames.
  101. Arguments:
  102. MacBindingHandle - A handle to use when calling NdisTransferData.
  103. MacReceiveContext - A context to use when calling NdisTransferData.
  104. RemoteAddress - The local target this packet was received from.
  105. MacOptions - The MAC options for the underlying NDIS binding.
  106. LookaheadBuffer - The lookahead buffer, starting at the IPX
  107. header.
  108. LookaheadBufferSize - The length of the lookahead data.
  109. LookaheadBufferOffset - The offset to add when calling
  110. NdisTransferData.
  111. PacketSize - The total length of the packet, starting at the
  112. IPX header.
  113. Return Value:
  114. None.
  115. --*/
  116. {
  117. NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
  118. NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
  119. PCONNECTION Connection;
  120. PREQUEST Request;
  121. PDEVICE Device = NbiDevice;
  122. ULONG Hash;
  123. ULONG ReceiveFlags;
  124. ULONG IndicateBytesTransferred = 0;
  125. ULONG DataAvailable, DataIndicated;
  126. ULONG DestBytes, BytesToTransfer;
  127. PUCHAR DataHeader;
  128. BOOLEAN Last, CompleteReceive, EndOfMessage, PartialReceive, CopyLookahead;
  129. NTSTATUS Status;
  130. NDIS_STATUS NdisStatus;
  131. ULONG NdisBytesTransferred;
  132. PIRP ReceiveIrp;
  133. PSLIST_ENTRY s;
  134. PNB_RECEIVE_RESERVED ReceiveReserved;
  135. PNDIS_PACKET Packet;
  136. PNDIS_BUFFER BufferChain;
  137. ULONG BufferChainLength;
  138. NB_DEFINE_LOCK_HANDLE (LockHandle)
  139. CTELockHandle CancelLH;
  140. if (Sess->DestConnectionId != 0xffff) {
  141. //
  142. // This is an active connection, find it using
  143. // our session id.
  144. //
  145. Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
  146. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  147. Connection = Device->ConnectionHash[Hash].Connections;
  148. while (Connection != NULL) {
  149. if (Connection->LocalConnectionId == Sess->DestConnectionId) {
  150. break;
  151. }
  152. Connection = Connection->NextConnection;
  153. }
  154. if (Connection == NULL) {
  155. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  156. return;
  157. }
  158. NbiReferenceConnectionLock (Connection, CREF_INDICATE);
  159. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  160. //
  161. // See what is happening with this connection.
  162. //
  163. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  164. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  165. #ifdef RSRC_TIMEOUT_DBG
  166. if ( Connection->FirstMessageRequest && NbiGlobalDebugResTimeout ) {
  167. LARGE_INTEGER CurrentTime, ElapsedTime;
  168. KeQuerySystemTime(&CurrentTime);
  169. ElapsedTime.QuadPart = CurrentTime.QuadPart - Connection->FirstMessageRequestTime.QuadPart;
  170. // DbgPrint("*****Elapsed %lx.%lx time\n",ElapsedTime.HighPart,ElapsedTime.LowPart);
  171. if ( ElapsedTime.QuadPart > NbiGlobalMaxResTimeout.QuadPart ) {
  172. DbgPrint("*****Connection %lx is not copleting irp %lx for %lx.%lx time\n",Connection, Connection->FirstMessageRequest,
  173. ElapsedTime.HighPart,ElapsedTime.LowPart);
  174. DbgPrint("************irp arrived at %lx.%lx current time %lx.%lx\n",
  175. Connection->FirstMessageRequestTime.HighPart,Connection->FirstMessageRequestTime.LowPart,
  176. CurrentTime.HighPart, CurrentTime.LowPart);
  177. NbiSendDeathPacket( Connection, LockHandle );
  178. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  179. }
  180. }
  181. #endif //RSRC_TIMEOUT_DBG
  182. //
  183. // The connection is up, see if this is data should
  184. // be received.
  185. //
  186. if (Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) {
  187. //
  188. // This is an ack. This call releases the lock.
  189. //
  190. NbiProcessDataAck(
  191. Connection,
  192. Sess,
  193. RemoteAddress
  194. NB_LOCK_HANDLE_ARG (LockHandle)
  195. );
  196. } else {
  197. //
  198. // See if there is any piggyback ack here.
  199. //
  200. if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
  201. //
  202. // We are waiting for an ack, so see if this acks
  203. // anything. Even the old netbios sometimes piggyback
  204. // acks (and doesn't send the explicit ack).
  205. //
  206. // This releases the lock.
  207. //
  208. NbiReframeConnection(
  209. Connection,
  210. Sess->ReceiveSequence,
  211. Sess->BytesReceived,
  212. FALSE
  213. NB_LOCK_HANDLE_ARG(LockHandle));
  214. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  215. if (Connection->State != CONNECTION_STATE_ACTIVE) {
  216. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  217. NbiDereferenceConnection (Connection, CREF_INDICATE);
  218. return;
  219. }
  220. } else if ((Connection->NewNetbios) &&
  221. (Connection->CurrentSend.SendSequence != Connection->UnAckedSend.SendSequence)) {
  222. //
  223. // For the new netbios, even if we are not waiting
  224. // for an ack he may have acked something with this
  225. // send and we should check, since it may allow
  226. // us to open our send window.
  227. //
  228. // This releases the lock.
  229. //
  230. NbiReframeConnection(
  231. Connection,
  232. Sess->ReceiveSequence,
  233. Sess->BytesReceived,
  234. FALSE
  235. NB_LOCK_HANDLE_ARG(LockHandle));
  236. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  237. if (Connection->State != CONNECTION_STATE_ACTIVE) {
  238. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  239. NbiDereferenceConnection (Connection, CREF_INDICATE);
  240. return;
  241. }
  242. }
  243. //
  244. // This is data on the connection. First make sure
  245. // it is the data we expect next.
  246. //
  247. if (Connection->NewNetbios) {
  248. if (Sess->SendSequence != Connection->ReceiveSequence) {
  249. ++Connection->ConnectionInfo.ReceiveErrors;
  250. ++Device->Statistics.DataFramesRejected;
  251. ADD_TO_LARGE_INTEGER(
  252. &Device->Statistics.DataFrameBytesRejected,
  253. PacketSize - sizeof(NB_CONNECTION));
  254. if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
  255. (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
  256. NB_ACK_TYPE AckType;
  257. NB_DEBUG2 (RECEIVE, ("Got unexp data on %lx, %x(%d) expect %x(%d)\n",
  258. Connection, Sess->SendSequence, Sess->Offset,
  259. Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
  260. //
  261. // If we are receiving a packet we have already seen, just
  262. // send a normal ack, otherwise force a resend. This test
  263. // we do is equivalent to
  264. // Sess->SendSequence < Connection->ReceiveSequence
  265. // but rearranged so it works when the numbers wrap.
  266. //
  267. if ((SHORT)(Sess->SendSequence - Connection->ReceiveSequence) < 0) {
  268. //
  269. // Since this is a resend, check if the local
  270. // target has changed.
  271. //
  272. #if defined(_PNP_POWER)
  273. if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, sizeof(IPX_LOCAL_TARGET))) {
  274. #if DBG
  275. DbgPrint ("NBI: Switch local target for %lx, (%d,%d)\n", Connection,
  276. Connection->LocalTarget.NicHandle.NicId, RemoteAddress->NicHandle.NicId);
  277. #endif
  278. Connection->LocalTarget = *RemoteAddress;
  279. }
  280. #else
  281. if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
  282. #if DBG
  283. DbgPrint ("NBI: Switch local target for %lx\n", Connection);
  284. #endif
  285. Connection->LocalTarget = *RemoteAddress;
  286. }
  287. #endif _PNP_POWER
  288. AckType = NbiAckResponse;
  289. } else {
  290. AckType = NbiAckResend;
  291. }
  292. //
  293. // This frees the lock.
  294. //
  295. NbiSendDataAck(
  296. Connection,
  297. AckType
  298. NB_LOCK_HANDLE_ARG(LockHandle));
  299. } else {
  300. NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
  301. Connection, Connection->ReceiveState,
  302. Sess->SendSequence, Sess->Offset,
  303. Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
  304. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  305. }
  306. NbiDereferenceConnection (Connection, CREF_INDICATE);
  307. return;
  308. }
  309. } else {
  310. //
  311. // Old netbios.
  312. //
  313. if ((Sess->SendSequence != Connection->ReceiveSequence) ||
  314. (Sess->Offset != Connection->CurrentReceive.MessageOffset)) {
  315. ++Connection->ConnectionInfo.ReceiveErrors;
  316. ++Device->Statistics.DataFramesRejected;
  317. ADD_TO_LARGE_INTEGER(
  318. &Device->Statistics.DataFrameBytesRejected,
  319. PacketSize - sizeof(NB_CONNECTION));
  320. if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
  321. (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
  322. NB_ACK_TYPE AckType;
  323. NB_DEBUG2 (RECEIVE, ("Got unexp on %lx, %x(%d) expect %x(%d)\n",
  324. Connection, Sess->SendSequence, Sess->Offset,
  325. Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
  326. //
  327. // If we are receiving the last packet again, just
  328. // send a normal ack, otherwise force a resend.
  329. //
  330. if (((Sess->SendSequence == Connection->ReceiveSequence) &&
  331. ((ULONG)(Sess->Offset + Sess->DataLength) == Connection->CurrentReceive.MessageOffset)) ||
  332. (Sess->SendSequence == (USHORT)(Connection->ReceiveSequence-1))) {
  333. AckType = NbiAckResponse;
  334. } else {
  335. AckType = NbiAckResend;
  336. }
  337. //
  338. // This frees the lock.
  339. //
  340. NbiSendDataAck(
  341. Connection,
  342. AckType
  343. NB_LOCK_HANDLE_ARG(LockHandle));
  344. } else {
  345. NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
  346. Connection, Connection->ReceiveState,
  347. Sess->SendSequence, Sess->Offset,
  348. Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
  349. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  350. }
  351. NbiDereferenceConnection (Connection, CREF_INDICATE);
  352. return;
  353. }
  354. }
  355. DataAvailable = PacketSize - sizeof(NB_CONNECTION);
  356. DataIndicated = LookaheadBufferSize - sizeof(NB_CONNECTION);
  357. DataHeader = LookaheadBuffer + sizeof(NB_CONNECTION);
  358. ++Device->TempFramesReceived;
  359. Device->TempFrameBytesReceived += DataAvailable;
  360. if (Connection->CurrentIndicateOffset) {
  361. CTEAssert (DataAvailable >= Connection->CurrentIndicateOffset);
  362. DataAvailable -= Connection->CurrentIndicateOffset;
  363. if (DataIndicated >= Connection->CurrentIndicateOffset) {
  364. DataIndicated -= Connection->CurrentIndicateOffset;
  365. } else {
  366. DataIndicated = 0;
  367. }
  368. DataHeader += Connection->CurrentIndicateOffset;
  369. }
  370. CopyLookahead = (BOOLEAN)(MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA);
  371. if (Connection->NewNetbios) {
  372. Last = (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_EOM) != 0);
  373. } else {
  374. Last = (BOOLEAN)(Sess->Offset + Sess->DataLength == Sess->TotalDataLength);
  375. }
  376. Connection->CurrentReceiveNoPiggyback =
  377. (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) != 0);
  378. if (Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) {
  379. //
  380. // We don't have a receive posted, so see if we can
  381. // get one from the queue or our client.
  382. //
  383. if (Connection->ReceiveQueue.Head != NULL) {
  384. PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
  385. Request = Connection->ReceiveQueue.Head;
  386. Connection->ReceiveQueue.Head = REQUEST_SINGLE_LINKAGE(Request);
  387. Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
  388. Connection->ReceiveRequest = Request;
  389. ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
  390. (REQUEST_PARAMETERS(Request));
  391. Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
  392. //
  393. // If there is a send in progress, then we assume
  394. // we are not in straight request-response mode
  395. // and disable piggybacking of this ack.
  396. //
  397. if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
  398. Connection->NoPiggybackHeuristic = TRUE;
  399. } else {
  400. Connection->NoPiggybackHeuristic = (BOOLEAN)
  401. ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
  402. }
  403. Connection->CurrentReceive.Offset = 0;
  404. Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
  405. Connection->CurrentReceive.BufferOffset = 0;
  406. NB_DEBUG2 (RECEIVE, ("Activated receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
  407. //
  408. // Fall through the if and process the data.
  409. //
  410. } else {
  411. if ((Connection->ReceiveUnaccepted == 0) &&
  412. (Connection->AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE])) {
  413. Connection->ReceiveState = CONNECTION_RECEIVE_INDICATE;
  414. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  415. ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
  416. if (Last) {
  417. ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
  418. }
  419. if (CopyLookahead) {
  420. ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
  421. }
  422. Status = (*Connection->AddressFile->ReceiveHandler)(
  423. Connection->AddressFile->HandlerContexts[TDI_EVENT_RECEIVE],
  424. Connection->Context,
  425. ReceiveFlags,
  426. DataIndicated,
  427. DataAvailable,
  428. &IndicateBytesTransferred,
  429. DataHeader,
  430. &ReceiveIrp);
  431. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  432. //
  433. // We got an IRP, activate it.
  434. //
  435. Request = NbiAllocateRequest (Device, ReceiveIrp);
  436. IF_NOT_ALLOCATED(Request) {
  437. ReceiveIrp->IoStatus.Information = 0;
  438. ReceiveIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  439. IoCompleteRequest (ReceiveIrp, IO_NETWORK_INCREMENT);
  440. Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
  441. if (Connection->NewNetbios) {
  442. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  443. Connection->LocalRcvSequenceMax =
  444. (USHORT)(Connection->ReceiveSequence - 1);
  445. //
  446. // This releases the lock.
  447. //
  448. NbiSendDataAck(
  449. Connection,
  450. NbiAckResponse
  451. NB_LOCK_HANDLE_ARG(LockHandle));
  452. }
  453. NbiDereferenceConnection (Connection, CREF_INDICATE);
  454. return;
  455. }
  456. CTEAssert (REQUEST_OPEN_CONTEXT(Request) == Connection);
  457. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  458. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  459. PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
  460. Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
  461. Connection->ReceiveUnaccepted = DataAvailable - IndicateBytesTransferred;
  462. Connection->ReceiveRequest = Request;
  463. ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
  464. (REQUEST_PARAMETERS(Request));
  465. Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
  466. //
  467. // If there is a send in progress, then we assume
  468. // we are not in straight request-response mode
  469. // and disable piggybacking of this ack.
  470. //
  471. if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
  472. Connection->NoPiggybackHeuristic = TRUE;
  473. } else {
  474. Connection->NoPiggybackHeuristic = (BOOLEAN)
  475. ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
  476. }
  477. Connection->CurrentReceive.Offset = 0;
  478. Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
  479. Connection->CurrentReceive.BufferOffset = 0;
  480. NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
  481. NB_DEBUG2 (RECEIVE, ("Indicate got receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
  482. //
  483. // Fall through the if and process the data.
  484. //
  485. } else {
  486. //
  487. // The connection has been stopped.
  488. //
  489. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  490. NbiDereferenceConnection (Connection, CREF_INDICATE);
  491. return;
  492. }
  493. } else if (Status == STATUS_SUCCESS) {
  494. //
  495. // He accepted some or all of the data.
  496. //
  497. NB_DEBUG2 (RECEIVE, ("Indicate took receive data %lx (%d)\n", Connection, Connection->ReceiveSequence));
  498. if ( (IndicateBytesTransferred >= DataAvailable)) {
  499. CTEAssert (IndicateBytesTransferred == DataAvailable);
  500. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  501. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  502. ++Connection->ReceiveSequence;
  503. ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
  504. Connection->CurrentIndicateOffset = 0;
  505. if ( Last ) {
  506. Connection->CurrentReceive.MessageOffset = 0;
  507. } else {
  508. Connection->CurrentReceive.MessageOffset+= IndicateBytesTransferred;
  509. }
  510. ++Connection->ConnectionInfo.ReceivedTsdus;
  511. //
  512. // If there is a send in progress, then we assume
  513. // we are not in straight request-response mode
  514. // and disable piggybacking of this ack.
  515. //
  516. Connection->NoPiggybackHeuristic = (BOOLEAN)
  517. (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE);
  518. Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
  519. Connection->ReceiveRequest = NULL;
  520. //
  521. // This releases the lock.
  522. //
  523. NbiAcknowledgeReceive(
  524. Connection
  525. NB_LOCK_HANDLE_ARG(LockHandle));
  526. } else {
  527. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  528. }
  529. } else {
  530. //
  531. // We will do the easiest thing here, which
  532. // is to send an ack for the amount he
  533. // took, and force a retransmit on the
  534. // remote. For net netbios we make a note
  535. // of how many bytes were taken and ask
  536. // for a resend.
  537. //
  538. #if DBG
  539. DbgPrint ("NBI: Client took partial indicate data\n");
  540. #endif
  541. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  542. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  543. Connection->CurrentReceive.MessageOffset +=
  544. IndicateBytesTransferred;
  545. Connection->ReceiveUnaccepted =
  546. DataAvailable - IndicateBytesTransferred;
  547. Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
  548. if (Connection->NewNetbios) {
  549. Connection->CurrentIndicateOffset = IndicateBytesTransferred;
  550. //
  551. // NOTE: We don't advance ReceiveSequence
  552. //
  553. }
  554. //
  555. // This releases the lock.
  556. //
  557. NbiSendDataAck(
  558. Connection,
  559. Connection->NewNetbios ?
  560. NbiAckResend : NbiAckResponse
  561. NB_LOCK_HANDLE_ARG(LockHandle));
  562. } else {
  563. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  564. }
  565. }
  566. NbiDereferenceConnection (Connection, CREF_INDICATE);
  567. return;
  568. } else {
  569. //
  570. // No IRP returned.
  571. //
  572. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  573. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  574. Connection->ReceiveUnaccepted = DataAvailable;
  575. Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
  576. NB_DEBUG (RECEIVE, ("Indicate got no receive on %lx (%lx)\n", Connection, Status));
  577. if (Connection->NewNetbios) {
  578. Connection->LocalRcvSequenceMax =
  579. (USHORT)(Connection->ReceiveSequence - 1);
  580. //
  581. // This releases the lock.
  582. //
  583. NbiSendDataAck(
  584. Connection,
  585. NbiAckResponse
  586. NB_LOCK_HANDLE_ARG(LockHandle));
  587. } else {
  588. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  589. }
  590. } else {
  591. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  592. }
  593. NbiDereferenceConnection (Connection, CREF_INDICATE);
  594. return;
  595. }
  596. } else {
  597. //
  598. // No receive handler.
  599. //
  600. Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
  601. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  602. if (Connection->ReceiveUnaccepted == 0) {
  603. NB_DEBUG (RECEIVE, ("No receive, no handler on %lx\n", Connection));
  604. } else {
  605. NB_DEBUG (RECEIVE, ("No receive, ReceiveUnaccepted %d on %lx\n",
  606. Connection->ReceiveUnaccepted, Connection));
  607. }
  608. if (Connection->NewNetbios) {
  609. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  610. Connection->LocalRcvSequenceMax =
  611. (USHORT)(Connection->ReceiveSequence - 1);
  612. //
  613. // This releases the lock.
  614. //
  615. NbiSendDataAck(
  616. Connection,
  617. NbiAckResponse
  618. NB_LOCK_HANDLE_ARG(LockHandle));
  619. }
  620. NbiDereferenceConnection (Connection, CREF_INDICATE);
  621. return;
  622. }
  623. }
  624. } else if (Connection->ReceiveState != CONNECTION_RECEIVE_ACTIVE) {
  625. //
  626. // If we have a transfer in progress, or are waiting for
  627. // a receive to be posted, then ignore this frame.
  628. //
  629. NB_DEBUG2 (RECEIVE, ("Got data on %lx, state %d (%d)\n", Connection, Connection->ReceiveState, Connection->ReceiveSequence));
  630. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  631. NbiDereferenceConnection (Connection, CREF_INDICATE);
  632. return;
  633. }
  634. else if (Connection->ReceiveUnaccepted)
  635. {
  636. //
  637. // Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE
  638. // &&
  639. // Connection->ReceiveUnaccepted
  640. //
  641. Connection->ReceiveUnaccepted += DataAvailable;
  642. }
  643. //
  644. // At this point we have a receive and it is set to
  645. // the correct current location.
  646. //
  647. DestBytes = Connection->ReceiveLength - Connection->CurrentReceive.Offset;
  648. BytesToTransfer = DataAvailable - IndicateBytesTransferred;
  649. if (DestBytes < BytesToTransfer) {
  650. //
  651. // If the data overflows the current receive, then make a
  652. // note that we should complete the receive at the end of
  653. // transfer data, but with EOR false.
  654. //
  655. EndOfMessage = FALSE;
  656. CompleteReceive = TRUE;
  657. PartialReceive = TRUE;
  658. BytesToTransfer = DestBytes;
  659. } else if (DestBytes == BytesToTransfer) {
  660. //
  661. // If the data just fills the current receive, then complete
  662. // the receive; EOR depends on whether this is a DOL or not.
  663. //
  664. EndOfMessage = Last;
  665. CompleteReceive = TRUE;
  666. PartialReceive = FALSE;
  667. } else {
  668. //
  669. // Complete the receive if this is a DOL.
  670. //
  671. EndOfMessage = Last;
  672. CompleteReceive = Last;
  673. PartialReceive = FALSE;
  674. }
  675. //
  676. // If we can copy the data directly, then update our
  677. // pointers, send an ack, and do the copy.
  678. //
  679. if ((BytesToTransfer > 0) &&
  680. (IndicateBytesTransferred + BytesToTransfer <= DataIndicated)) {
  681. ULONG BytesNow, BytesLeft;
  682. PUCHAR CurTarget = NULL, CurSource;
  683. ULONG CurTargetLen;
  684. PNDIS_BUFFER CurBuffer;
  685. ULONG CurByteOffset;
  686. NB_DEBUG2 (RECEIVE, ("Direct copy of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
  687. Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
  688. CurBuffer = Connection->CurrentReceive.Buffer;
  689. CurByteOffset = Connection->CurrentReceive.BufferOffset;
  690. CurSource = DataHeader + IndicateBytesTransferred;
  691. BytesLeft = BytesToTransfer;
  692. NdisQueryBufferSafe (CurBuffer, &CurTarget, &CurTargetLen, HighPagePriority);
  693. if (CurTarget)
  694. {
  695. CurTarget += CurByteOffset;
  696. CurTargetLen -= CurByteOffset;
  697. }
  698. while (CurTarget) {
  699. if (CurTargetLen < BytesLeft) {
  700. BytesNow = CurTargetLen;
  701. } else {
  702. BytesNow = BytesLeft;
  703. }
  704. TdiCopyLookaheadData(
  705. CurTarget,
  706. CurSource,
  707. BytesNow,
  708. CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
  709. if (BytesNow == CurTargetLen) {
  710. BytesLeft -= BytesNow;
  711. CurBuffer = CurBuffer->Next;
  712. CurByteOffset = 0;
  713. if (BytesLeft > 0) {
  714. NdisQueryBufferSafe (CurBuffer, &CurTarget, &CurTargetLen, HighPagePriority);
  715. CurSource += BytesNow;
  716. } else {
  717. break;
  718. }
  719. } else {
  720. CurByteOffset += BytesNow;
  721. CTEAssert (BytesLeft == BytesNow);
  722. break;
  723. }
  724. }
  725. Connection->CurrentReceive.Buffer = CurBuffer;
  726. Connection->CurrentReceive.BufferOffset = CurByteOffset;
  727. Connection->CurrentReceive.Offset += BytesToTransfer;
  728. Connection->CurrentReceive.MessageOffset += BytesToTransfer;
  729. //
  730. // Release and re-acquire the lock, but this time with the
  731. // Cancel lock
  732. //
  733. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  734. NB_GET_CANCEL_LOCK( &CancelLH );
  735. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  736. if (CompleteReceive ||
  737. (Connection->State != CONNECTION_STATE_ACTIVE)) {
  738. if (EndOfMessage) {
  739. CTEAssert (!PartialReceive);
  740. ++Connection->ReceiveSequence;
  741. ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
  742. Connection->CurrentReceive.MessageOffset = 0;
  743. Connection->CurrentIndicateOffset = 0;
  744. } else if (Connection->NewNetbios) {
  745. if (PartialReceive) {
  746. Connection->CurrentIndicateOffset += BytesToTransfer;
  747. } else {
  748. ++Connection->ReceiveSequence;
  749. ++Connection->LocalRcvSequenceMax;
  750. Connection->CurrentIndicateOffset = 0;
  751. }
  752. }
  753. //
  754. // This sends an ack and releases the connection lock.
  755. // and CANCEL Lock.
  756. //
  757. NbiCompleteReceive(
  758. Connection,
  759. EndOfMessage,
  760. CancelLH
  761. NB_LOCK_HANDLE_ARG(LockHandle));
  762. } else {
  763. NB_SYNC_SWAP_IRQL( CancelLH, LockHandle);
  764. NB_FREE_CANCEL_LOCK( CancelLH );
  765. //
  766. // CompleteReceive is FALSE, so EndOfMessage is FALSE.
  767. //
  768. Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
  769. //
  770. // This releases the lock.
  771. //
  772. if (Connection->NewNetbios) {
  773. //
  774. // A partial receive should only happen if we are
  775. // completing the receive.
  776. //
  777. CTEAssert (!PartialReceive);
  778. ++Connection->ReceiveSequence;
  779. ++Connection->LocalRcvSequenceMax;
  780. Connection->CurrentIndicateOffset = 0;
  781. if ((Connection->CurrentReceiveNoPiggyback) ||
  782. ((Device->AckWindow != 0) &&
  783. (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
  784. NbiSendDataAck(
  785. Connection,
  786. NbiAckResponse
  787. NB_LOCK_HANDLE_ARG(LockHandle));
  788. } else {
  789. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  790. }
  791. } else {
  792. NbiSendDataAck(
  793. Connection,
  794. NbiAckResponse
  795. NB_LOCK_HANDLE_ARG(LockHandle));
  796. }
  797. }
  798. NbiDereferenceConnection (Connection, CREF_INDICATE);
  799. return;
  800. }
  801. //
  802. // We have to set up a call to transfer data and send
  803. // the ack after it completes (if it succeeds).
  804. //
  805. s = NbiPopReceivePacket (Device);
  806. if (s == NULL) {
  807. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  808. ++Connection->ConnectionInfo.ReceiveErrors;
  809. ++Device->Statistics.DataFramesRejected;
  810. ADD_TO_LARGE_INTEGER(
  811. &Device->Statistics.DataFrameBytesRejected,
  812. DataAvailable);
  813. NbiDereferenceConnection (Connection, CREF_INDICATE);
  814. return;
  815. }
  816. ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
  817. Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
  818. //
  819. // Initialize the receive packet.
  820. //
  821. ReceiveReserved->u.RR_CO.Connection = Connection;
  822. ReceiveReserved->u.RR_CO.EndOfMessage = EndOfMessage;
  823. ReceiveReserved->u.RR_CO.CompleteReceive = CompleteReceive;
  824. ReceiveReserved->u.RR_CO.PartialReceive = PartialReceive;
  825. ReceiveReserved->Type = RECEIVE_TYPE_DATA;
  826. CTEAssert (!ReceiveReserved->TransferInProgress);
  827. ReceiveReserved->TransferInProgress = TRUE;
  828. //
  829. // if we've got zero bytes left, avoid the TransferData below and
  830. // just deliver.
  831. //
  832. if (BytesToTransfer <= 0) {
  833. ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
  834. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  835. NB_DEBUG2 (RECEIVE, ("TransferData of 0 bytes %lx (%d)\n", Connection, Connection->ReceiveSequence));
  836. NbiTransferDataComplete(
  837. Packet,
  838. NDIS_STATUS_SUCCESS,
  839. 0);
  840. return;
  841. }
  842. //
  843. // If needed, build a buffer chain to describe this
  844. // to NDIS.
  845. //
  846. Connection->PreviousReceive = Connection->CurrentReceive;
  847. if ((Connection->CurrentReceive.Offset == 0) &&
  848. CompleteReceive) {
  849. BufferChain = Connection->CurrentReceive.Buffer;
  850. BufferChainLength = BytesToTransfer;
  851. Connection->CurrentReceive.Buffer = NULL;
  852. ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
  853. } else {
  854. if (NbiBuildBufferChainFromBufferChain (
  855. Device->NdisBufferPoolHandle,
  856. Connection->CurrentReceive.Buffer,
  857. Connection->CurrentReceive.BufferOffset,
  858. BytesToTransfer,
  859. &BufferChain,
  860. &Connection->CurrentReceive.Buffer,
  861. &Connection->CurrentReceive.BufferOffset,
  862. &BufferChainLength) != NDIS_STATUS_SUCCESS) {
  863. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  864. NB_DEBUG2 (RECEIVE, ("Could not build receive buffer chain %lx (%d)\n", Connection, Connection->ReceiveSequence));
  865. NbiDereferenceConnection (Connection, CREF_INDICATE);
  866. return;
  867. }
  868. ReceiveReserved->u.RR_CO.NoNdisBuffer = FALSE;
  869. }
  870. NdisChainBufferAtFront (Packet, BufferChain);
  871. Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
  872. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  873. NB_DEBUG2 (RECEIVE, ("TransferData of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
  874. (*Device->Bind.TransferDataHandler) (
  875. &NdisStatus,
  876. MacBindingHandle,
  877. MacReceiveContext,
  878. LookaheadBufferOffset + sizeof(NB_CONNECTION) +
  879. Connection->CurrentIndicateOffset + IndicateBytesTransferred,
  880. BytesToTransfer,
  881. Packet,
  882. (PUINT)&NdisBytesTransferred);
  883. if (NdisStatus != NDIS_STATUS_PENDING) {
  884. #if DBG
  885. if (NdisStatus == STATUS_SUCCESS) {
  886. CTEAssert (NdisBytesTransferred == BytesToTransfer);
  887. }
  888. #endif
  889. NbiTransferDataComplete (
  890. Packet,
  891. NdisStatus,
  892. NdisBytesTransferred);
  893. }
  894. return;
  895. }
  896. } else if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
  897. (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
  898. //
  899. // If this is the ack for the session initialize, then
  900. // complete the pending connects. This routine releases
  901. // the connection lock.
  902. //
  903. NbiProcessSessionInitAck(
  904. Connection,
  905. Sess
  906. NB_LOCK_HANDLE_ARG(LockHandle));
  907. } else {
  908. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  909. }
  910. NbiDereferenceConnection (Connection, CREF_INDICATE);
  911. } else {
  912. //
  913. // This is a session initialize frame.
  914. //
  915. // If there is more data than in the lookahead
  916. // buffer, we won't be able to echo it back in the
  917. // response.
  918. //
  919. NbiProcessSessionInitialize(
  920. RemoteAddress,
  921. MacOptions,
  922. LookaheadBuffer,
  923. LookaheadBufferSize);
  924. }
  925. } /* NbiProcessSessionData */
  926. VOID
  927. NbiProcessDataAck(
  928. IN PCONNECTION Connection,
  929. IN NB_SESSION UNALIGNED * Sess,
  930. IN PIPX_LOCAL_TARGET RemoteAddress
  931. NB_LOCK_HANDLE_PARAM(LockHandle)
  932. )
  933. /*++
  934. Routine Description:
  935. This routine processes an ack on an active connection.
  936. NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
  937. AND RETURNS WITH IT RELEASED.
  938. Arguments:
  939. Connection - The connection.
  940. Sess - The session frame.
  941. RemoteAddress - The local target this packet was received from.
  942. LockHandle - The handle used to acquire the lock.
  943. Return Value:
  944. NTSTATUS - status of operation.
  945. --*/
  946. {
  947. BOOLEAN Resend;
  948. //
  949. // Make sure we expect an ack right now.
  950. //
  951. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  952. if (((Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) ||
  953. (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W)) &&
  954. ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
  955. //
  956. // We are waiting for an ack (because we completed
  957. // packetizing a send, or ran out of receive window).
  958. //
  959. // This will complete any sends that are acked by
  960. // this receive, and if necessary readjust the
  961. // send pointer and requeue the connection for
  962. // packetizing. It release the connection lock.
  963. //
  964. if (Connection->ResponseTimeout) {
  965. Resend = TRUE;
  966. Connection->ResponseTimeout = FALSE;
  967. } else {
  968. Resend = (BOOLEAN)
  969. ((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0);
  970. }
  971. NbiReframeConnection(
  972. Connection,
  973. Sess->ReceiveSequence,
  974. Sess->BytesReceived,
  975. Resend
  976. NB_LOCK_HANDLE_ARG(LockHandle));
  977. } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) &&
  978. ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
  979. //
  980. // We had a probe outstanding and got a response. Restart
  981. // the connection if needed (a send may have just been
  982. // posted while the probe was outstanding).
  983. //
  984. // We should check that the response is really correct.
  985. //
  986. if (Connection->NewNetbios) {
  987. Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
  988. }
  989. NbiRestartConnection (Connection);
  990. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  991. } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE) &&
  992. ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
  993. if (Connection->NewNetbios) {
  994. //
  995. // We are packetizing, reframe. In the unlikely
  996. // event that this acks everything we may packetize
  997. // in this call, but that is OK (the other thread
  998. // will exit if we finish up). More normally we
  999. // will just advance UnAcked send a bit.
  1000. //
  1001. NbiReframeConnection(
  1002. Connection,
  1003. Sess->ReceiveSequence,
  1004. Sess->BytesReceived,
  1005. (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0)
  1006. NB_LOCK_HANDLE_ARG(LockHandle));
  1007. } else {
  1008. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1009. }
  1010. #if 0
  1011. //
  1012. // Should handle this case (i.e. may be in W_PACKET).
  1013. //
  1014. } else if ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0) {
  1015. DbgPrint ("NWLNKNB: Ignoring ack, state is %d\n", Connection->SubState);
  1016. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1017. #endif
  1018. } else {
  1019. //
  1020. // We got a probe from the remote. Some old DOS clients
  1021. // send probes that do not have the send ack bit on,
  1022. // so we respond to any probe if none of the conditions
  1023. // above are true. This call releases the lock.
  1024. //
  1025. // We use the IgnoreNextDosProbe flag to ignore every
  1026. // second probe of this nature, to avoid a data ack
  1027. // war between two machines who each think they are
  1028. // responding to the other. This flag is set to FALSE
  1029. // whenever we send an ack or a probe.
  1030. //
  1031. if (!Connection->IgnoreNextDosProbe) {
  1032. //
  1033. // Since this is a probe, check if the local
  1034. // target has changed.
  1035. //
  1036. if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
  1037. #if DBG
  1038. DbgPrint ("NBI: Switch local target for %lx\n", Connection);
  1039. #endif
  1040. Connection->LocalTarget = *RemoteAddress;
  1041. }
  1042. NbiSendDataAck(
  1043. Connection,
  1044. NbiAckResponse
  1045. NB_LOCK_HANDLE_ARG(LockHandle));
  1046. Connection->IgnoreNextDosProbe = TRUE;
  1047. } else {
  1048. Connection->IgnoreNextDosProbe = FALSE;
  1049. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1050. }
  1051. }
  1052. } else {
  1053. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1054. return;
  1055. }
  1056. } /* NbiProcessDataAck */
  1057. VOID
  1058. NbiProcessSessionInitialize(
  1059. IN PIPX_LOCAL_TARGET RemoteAddress,
  1060. IN ULONG MacOptions,
  1061. IN PUCHAR PacketBuffer,
  1062. IN UINT PacketSize
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. This routine handles NB_CMD_SESSION frames which have
  1067. a remote connection ID of 0xffff -- these are session
  1068. initialize frames.
  1069. Arguments:
  1070. RemoteAddress - The local target this packet was received from.
  1071. MacOptions - The MAC options for the underlying NDIS binding.
  1072. PacketBuffer - The packet data, starting at the IPX
  1073. header.
  1074. PacketSize - The total length of the packet, starting at the
  1075. IPX header.
  1076. Return Value:
  1077. None.
  1078. --*/
  1079. {
  1080. NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
  1081. NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
  1082. NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
  1083. CONNECT_INDICATION TempConnInd;
  1084. PCONNECT_INDICATION ConnInd;
  1085. PCONNECTION Connection;
  1086. PADDRESS Address;
  1087. PREQUEST Request, ListenRequest, AcceptRequest;
  1088. PDEVICE Device = NbiDevice;
  1089. PLIST_ENTRY p;
  1090. ULONG Hash;
  1091. TA_NETBIOS_ADDRESS SourceName;
  1092. PIRP AcceptIrp;
  1093. CONNECTION_CONTEXT ConnectionContext;
  1094. NTSTATUS AcceptStatus;
  1095. PADDRESS_FILE AddressFile, ReferencedAddressFile;
  1096. PTDI_REQUEST_KERNEL_LISTEN ListenParameters;
  1097. PTDI_CONNECTION_INFORMATION ListenInformation;
  1098. PTDI_CONNECTION_INFORMATION RemoteInformation;
  1099. TDI_ADDRESS_NETBIOS * ListenAddress;
  1100. NB_DEFINE_LOCK_HANDLE (LockHandle1)
  1101. NB_DEFINE_LOCK_HANDLE (LockHandle2)
  1102. NB_DEFINE_LOCK_HANDLE (LockHandle3)
  1103. CTELockHandle CancelLH;
  1104. //
  1105. // Verify that the whole packet is there.
  1106. //
  1107. if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT))) {
  1108. #if DBG
  1109. DbgPrint ("NBI: Got short session initialize, %d/%d\n", PacketSize,
  1110. sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
  1111. #endif
  1112. return;
  1113. }
  1114. //
  1115. // Verify that MaximumDataSize that remote can support is > 0
  1116. // Bug # 19405
  1117. //
  1118. if ( SessInit->MaximumDataSize == 0 ) {
  1119. NB_DEBUG(CONNECTION, ("Connect request with MaximumDataSize == 0\n"
  1120. ));
  1121. return;
  1122. }
  1123. //
  1124. // Make sure this is for an address we care about.
  1125. //
  1126. if (Device->AddressCounts[SessInit->DestinationName[0]] == 0) {
  1127. return;
  1128. }
  1129. Address = NbiFindAddress (Device, (PUCHAR)SessInit->DestinationName);
  1130. if (Address == NULL) {
  1131. return;
  1132. }
  1133. //
  1134. // First see if we have a session to this remote. We check
  1135. // this in case our ack of the session initialize was dropped,
  1136. // we don't want to reindicate our client.
  1137. //
  1138. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
  1139. for (Hash = 0; Hash < CONNECTION_HASH_COUNT; Hash++) {
  1140. Connection = Device->ConnectionHash[Hash].Connections;
  1141. while (Connection != NULL) {
  1142. if ((RtlEqualMemory (&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12)) &&
  1143. (Connection->RemoteConnectionId == Sess->SourceConnectionId) &&
  1144. (Connection->State != CONNECTION_STATE_DISCONNECT)) {
  1145. //
  1146. // Yes, we are talking to this remote, if it is active then
  1147. // respond, otherwise we are in the process of connecting
  1148. // and we will respond eventually.
  1149. //
  1150. #if DBG
  1151. DbgPrint ("NBI: Got connect request on active connection %lx\n", Connection);
  1152. #endif
  1153. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  1154. NbiReferenceConnectionLock (Connection, CREF_INDICATE);
  1155. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1156. NbiSendSessionInitAck(
  1157. Connection,
  1158. (PUCHAR)(SessInit+1),
  1159. PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT)),
  1160. NULL); // lock is not held
  1161. NbiDereferenceConnection (Connection, CREF_INDICATE);
  1162. } else {
  1163. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1164. }
  1165. NbiDereferenceAddress (Address, AREF_FIND);
  1166. return;
  1167. }
  1168. Connection = Connection->NextConnection;
  1169. }
  1170. }
  1171. TdiBuildNetbiosAddress ((PUCHAR)SessInit->SourceName, FALSE, &SourceName);
  1172. //
  1173. // Scan the queue of listens to see if there is one that
  1174. // satisfies this request.
  1175. //
  1176. // NOTE: The device lock is held here.
  1177. //
  1178. for (p = Device->ListenQueue.Flink;
  1179. p != &Device->ListenQueue;
  1180. p = p->Flink) {
  1181. Request = LIST_ENTRY_TO_REQUEST (p);
  1182. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1183. if (Connection->AddressFile->Address != Address) {
  1184. continue;
  1185. }
  1186. //
  1187. // Check that this listen is not specific to a different
  1188. // netbios name.
  1189. //
  1190. ListenParameters = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(Request);
  1191. ListenInformation = ListenParameters->RequestConnectionInformation;
  1192. if (ListenInformation &&
  1193. (ListenInformation->RemoteAddress) &&
  1194. (ListenAddress = NbiParseTdiAddress(ListenInformation->RemoteAddress, ListenInformation->RemoteAddressLength, FALSE)) &&
  1195. (!RtlEqualMemory(
  1196. SessInit->SourceName,
  1197. ListenAddress->NetbiosName,
  1198. 16))) {
  1199. continue;
  1200. }
  1201. //
  1202. // This connection is valid, so we use it.
  1203. //
  1204. NB_DEBUG2 (CONNECTION, ("Activating queued listen %lx\n", Connection));
  1205. RemoveEntryList (REQUEST_LINKAGE(Request));
  1206. RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
  1207. RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
  1208. Connection->LocalTarget = *RemoteAddress;
  1209. Connection->RemoteConnectionId = Sess->SourceConnectionId;
  1210. Connection->SessionInitAckDataLength =
  1211. PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
  1212. if (Connection->SessionInitAckDataLength > 0) {
  1213. if (Connection->SessionInitAckData = NbiAllocateMemory (Connection->SessionInitAckDataLength,
  1214. MEMORY_CONNECTION, "SessionInitAckData"))
  1215. {
  1216. RtlCopyMemory (Connection->SessionInitAckData,
  1217. (PUCHAR)(SessInit+1),
  1218. Connection->SessionInitAckDataLength);
  1219. }
  1220. else
  1221. {
  1222. Connection->SessionInitAckDataLength = 0;
  1223. }
  1224. }
  1225. Connection->MaximumPacketSize = SessInit->MaximumDataSize;
  1226. Connection->CurrentSend.SendSequence = 0;
  1227. Connection->UnAckedSend.SendSequence = 0;
  1228. Connection->RetransmitThisWindow = FALSE;
  1229. Connection->ReceiveSequence = 1;
  1230. Connection->CurrentReceive.MessageOffset = 0;
  1231. Connection->Retries = Device->KeepAliveCount;
  1232. if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
  1233. Connection->NewNetbios = TRUE;
  1234. Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
  1235. Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
  1236. Connection->SendWindowSequenceLimit = 2;
  1237. if (Connection->RemoteRcvSequenceMax == 0) {
  1238. Connection->RemoteRcvSequenceMax = 1;
  1239. }
  1240. } else {
  1241. Connection->NewNetbios = FALSE;
  1242. }
  1243. //
  1244. // Save this information now for whenever we complete the listen.
  1245. //
  1246. RemoteInformation = ListenParameters->ReturnConnectionInformation;
  1247. if (RemoteInformation != NULL) {
  1248. RtlCopyMemory(
  1249. (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
  1250. &SourceName,
  1251. (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
  1252. RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
  1253. }
  1254. if (ListenParameters->RequestFlags & TDI_QUERY_ACCEPT) {
  1255. //
  1256. // We have to wait for an accept before sending the
  1257. // session init ack, so we complete the listen and wait.
  1258. //
  1259. ListenRequest = Request;
  1260. Connection->ListenRequest = NULL;
  1261. NB_DEBUG2 (CONNECTION, ("Queued listen on %lx awaiting accept\n", Connection));
  1262. Connection->SubState = CONNECTION_SUBSTATE_L_W_ACCEPT;
  1263. NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_W_ACCEPT);
  1264. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1265. } else {
  1266. //
  1267. // We are ready to go, so we send out the find route request
  1268. // for the remote. We keep the listen alive and the CREF_LISTEN
  1269. // reference on until this completes.
  1270. //
  1271. NB_DEBUG2 (CONNECTION, ("Activating queued listen on %lx\n", Connection));
  1272. ListenRequest = NULL;
  1273. Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
  1274. NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
  1275. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1276. *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
  1277. *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
  1278. RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
  1279. Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
  1280. Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
  1281. //
  1282. // When this completes, we will send the session init
  1283. // ack. We don't call it if the client is for network 0,
  1284. // instead just fake as if no route could be found
  1285. // and we will use the local target we got here.
  1286. //
  1287. if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
  1288. (*Device->Bind.FindRouteHandler)(
  1289. &Connection->FindRouteRequest);
  1290. } else {
  1291. NbiFindRouteComplete(
  1292. &Connection->FindRouteRequest,
  1293. FALSE);
  1294. }
  1295. }
  1296. //
  1297. // Complete the listen if needed.
  1298. //
  1299. if (ListenRequest != NULL) {
  1300. REQUEST_INFORMATION (ListenRequest) = 0;
  1301. REQUEST_STATUS (ListenRequest) = STATUS_SUCCESS;
  1302. NB_GET_CANCEL_LOCK ( &CancelLH );
  1303. IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
  1304. NB_FREE_CANCEL_LOCK( CancelLH );
  1305. NbiCompleteRequest (ListenRequest);
  1306. NbiFreeRequest (Device, ListenRequest);
  1307. }
  1308. NbiDereferenceAddress (Address, AREF_FIND);
  1309. return;
  1310. }
  1311. //
  1312. // We could not find a listen, so we indicate to every
  1313. // client. Make sure there is no session initialize for this
  1314. // remote being indicated. If there is not, we insert
  1315. // ourselves in the queue to block others.
  1316. //
  1317. // NOTE: The device lock is held here.
  1318. //
  1319. for (p = Device->ConnectIndicationInProgress.Flink;
  1320. p != &Device->ConnectIndicationInProgress;
  1321. p = p->Flink) {
  1322. ConnInd = CONTAINING_RECORD (p, CONNECT_INDICATION, Linkage);
  1323. if ((RtlEqualMemory(ConnInd->NetbiosName, SessInit->DestinationName, 16)) &&
  1324. (RtlEqualMemory(&ConnInd->RemoteAddress, Conn->IpxHeader.SourceNetwork, 12)) &&
  1325. (ConnInd->ConnectionId == Sess->SourceConnectionId)) {
  1326. //
  1327. // We are processing a request from this remote for
  1328. // the same ID, to avoid confusion we just exit.
  1329. //
  1330. #if DBG
  1331. DbgPrint ("NBI: Already processing connect to <%.16s>\n", SessInit->DestinationName);
  1332. #endif
  1333. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1334. NbiDereferenceAddress (Address, AREF_FIND);
  1335. return;
  1336. }
  1337. }
  1338. RtlCopyMemory (TempConnInd.NetbiosName, SessInit->DestinationName, 16);
  1339. RtlCopyMemory (&TempConnInd.RemoteAddress, Conn->IpxHeader.SourceNetwork, 12);
  1340. TempConnInd.ConnectionId = Sess->SourceConnectionId;
  1341. InsertTailList (&Device->ConnectIndicationInProgress, &TempConnInd.Linkage);
  1342. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1343. //
  1344. // Now scan through the address to find someone who has
  1345. // an indication routine registed and wants this connection.
  1346. //
  1347. ReferencedAddressFile = NULL;
  1348. NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
  1349. for (p = Address->AddressFileDatabase.Flink;
  1350. p != &Address->AddressFileDatabase;
  1351. p = p->Flink) {
  1352. //
  1353. // Find the next open address file in the list.
  1354. //
  1355. AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
  1356. if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
  1357. continue;
  1358. }
  1359. NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
  1360. NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
  1361. if (ReferencedAddressFile != NULL) {
  1362. NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
  1363. }
  1364. ReferencedAddressFile = AddressFile;
  1365. //
  1366. // No posted listen requests; is there a kernel client?
  1367. //
  1368. if (AddressFile->RegisteredHandler[TDI_EVENT_CONNECT]) {
  1369. if ((*AddressFile->ConnectionHandler)(
  1370. AddressFile->HandlerContexts[TDI_EVENT_CONNECT],
  1371. sizeof (TA_NETBIOS_ADDRESS),
  1372. &SourceName,
  1373. 0, // user data
  1374. NULL,
  1375. 0, // options
  1376. NULL,
  1377. &ConnectionContext,
  1378. &AcceptIrp) != STATUS_MORE_PROCESSING_REQUIRED) {
  1379. //
  1380. // The client did not return a request, go to the
  1381. // next address file.
  1382. //
  1383. NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
  1384. continue;
  1385. }
  1386. AcceptRequest = NbiAllocateRequest (Device, AcceptIrp);
  1387. IF_NOT_ALLOCATED(AcceptRequest) {
  1388. AcceptStatus = STATUS_INSUFFICIENT_RESOURCES;
  1389. } else {
  1390. //
  1391. // The client accepted the connect, so activate
  1392. // the connection and complete the accept.
  1393. // listen. This lookup references the connection
  1394. // so we know it will remain valid.
  1395. //
  1396. Connection = NbiLookupConnectionByContext (
  1397. AddressFile,
  1398. ConnectionContext);
  1399. if (Connection != NULL) {
  1400. ASSERT (Connection->AddressFile == AddressFile);
  1401. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle2);
  1402. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
  1403. if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
  1404. (Connection->DisassociatePending == NULL) &&
  1405. (Connection->ClosePending == NULL)) {
  1406. NB_DEBUG2 (CONNECTION, ("Indication on %lx returned connection %lx\n", AddressFile, Connection));
  1407. Connection->State = CONNECTION_STATE_LISTENING;
  1408. Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
  1409. Connection->Retries = Device->KeepAliveCount;
  1410. RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
  1411. RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
  1412. Connection->LocalTarget = *RemoteAddress;
  1413. Connection->SessionInitAckDataLength =
  1414. PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
  1415. if (Connection->SessionInitAckDataLength > 0) {
  1416. if (Connection->SessionInitAckData = NbiAllocateMemory(
  1417. Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData"))
  1418. {
  1419. RtlCopyMemory (Connection->SessionInitAckData,
  1420. (PUCHAR)(SessInit+1),
  1421. Connection->SessionInitAckDataLength);
  1422. }
  1423. else
  1424. {
  1425. Connection->SessionInitAckDataLength = 0;
  1426. }
  1427. }
  1428. Connection->MaximumPacketSize = SessInit->MaximumDataSize;
  1429. (VOID)NbiAssignConnectionId (Device, Connection); // Check return code.
  1430. Connection->RemoteConnectionId = Sess->SourceConnectionId;
  1431. Connection->CurrentSend.SendSequence = 0;
  1432. Connection->UnAckedSend.SendSequence = 0;
  1433. Connection->RetransmitThisWindow = FALSE;
  1434. Connection->ReceiveSequence = 1;
  1435. Connection->CurrentReceive.MessageOffset = 0;
  1436. Connection->Retries = Device->KeepAliveCount;
  1437. if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
  1438. Connection->NewNetbios = TRUE;
  1439. Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
  1440. Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
  1441. Connection->SendWindowSequenceLimit = 2;
  1442. if (Connection->RemoteRcvSequenceMax == 0) {
  1443. Connection->RemoteRcvSequenceMax = 1;
  1444. }
  1445. } else {
  1446. Connection->NewNetbios = FALSE;
  1447. }
  1448. NbiReferenceConnectionLock (Connection, CREF_ACCEPT);
  1449. NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
  1450. Connection->AcceptRequest = AcceptRequest;
  1451. AcceptStatus = STATUS_PENDING;
  1452. //
  1453. // Take us out of this list now, we will jump to
  1454. // FoundConnection which is past the removal below.
  1455. //
  1456. RemoveEntryList (&TempConnInd.Linkage);
  1457. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1458. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
  1459. *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
  1460. *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
  1461. RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
  1462. Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
  1463. Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
  1464. //
  1465. // When this completes, we will send the session init
  1466. // ack. We don't call it if the client is for network 0,
  1467. // instead just fake as if no route could be found
  1468. // and we will use the local target we got here.
  1469. // The accept is completed when this completes.
  1470. //
  1471. if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
  1472. (*Device->Bind.FindRouteHandler)(
  1473. &Connection->FindRouteRequest);
  1474. } else {
  1475. NbiFindRouteComplete(
  1476. &Connection->FindRouteRequest,
  1477. FALSE);
  1478. }
  1479. } else {
  1480. NB_DEBUG (CONNECTION, ("Indication on %lx returned invalid connection %lx\n", AddressFile, Connection));
  1481. AcceptStatus = STATUS_INVALID_CONNECTION;
  1482. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1483. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
  1484. }
  1485. NbiDereferenceConnection (Connection, CREF_BY_CONTEXT);
  1486. } else {
  1487. NB_DEBUG (CONNECTION, ("Indication on %lx returned unknown connection %lx\n", AddressFile, Connection));
  1488. AcceptStatus = STATUS_INVALID_CONNECTION;
  1489. }
  1490. }
  1491. //
  1492. // Complete the accept request in the failure case.
  1493. //
  1494. if (AcceptStatus != STATUS_PENDING) {
  1495. REQUEST_STATUS (AcceptRequest) = AcceptStatus;
  1496. NbiCompleteRequest (AcceptRequest);
  1497. NbiFreeRequest (Device, AcceptRequest);
  1498. } else {
  1499. //
  1500. // We found a connection, so we break; this is
  1501. // a jump since the while exit assumes the
  1502. // address lock is held.
  1503. //
  1504. goto FoundConnection;
  1505. }
  1506. }
  1507. NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
  1508. } // end of for loop through the address files
  1509. NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
  1510. //
  1511. // Take us out of the list that blocks other indications
  1512. // from this remote to this address.
  1513. //
  1514. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
  1515. RemoveEntryList (&TempConnInd.Linkage);
  1516. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
  1517. FoundConnection:
  1518. if (ReferencedAddressFile != NULL) {
  1519. NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
  1520. }
  1521. NbiDereferenceAddress (Address, AREF_FIND);
  1522. } /* NbiProcessSessionInitialize */
  1523. VOID
  1524. NbiProcessSessionInitAck(
  1525. IN PCONNECTION Connection,
  1526. IN NB_SESSION UNALIGNED * Sess
  1527. IN NB_LOCK_HANDLE_PARAM(LockHandle)
  1528. )
  1529. /*++
  1530. Routine Description:
  1531. This routine handles session init ack frames.
  1532. THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
  1533. AND RETURNS WITH IT RELEASED.
  1534. Arguments:
  1535. Connection - The connection.
  1536. Sess - The netbios header for the received frame.
  1537. LockHandle - The handle with which Connection->Lock was acquired.
  1538. Return Value:
  1539. None.
  1540. --*/
  1541. {
  1542. PREQUEST Request;
  1543. NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
  1544. BOOLEAN TimerWasStopped = FALSE;
  1545. CTELockHandle CancelLH;
  1546. if ((Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) &&
  1547. (Sess->SendSequence == 0x0000) &&
  1548. (Sess->ReceiveSequence == 0x0001)) {
  1549. NB_DEBUG2 (CONNECTION, ("Completing connect on %lx\n", Connection));
  1550. if (CTEStopTimer (&Connection->Timer)) {
  1551. TimerWasStopped = TRUE;
  1552. }
  1553. Connection->State = CONNECTION_STATE_ACTIVE;
  1554. Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
  1555. Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
  1556. if (Connection->Retries == NbiDevice->ConnectionCount) {
  1557. ++NbiDevice->Statistics.ConnectionsAfterNoRetry;
  1558. } else {
  1559. ++NbiDevice->Statistics.ConnectionsAfterRetry;
  1560. }
  1561. ++NbiDevice->Statistics.OpenConnections;
  1562. Connection->Retries = NbiDevice->KeepAliveCount;
  1563. NbiStartWatchdog (Connection);
  1564. Connection->RemoteConnectionId = Sess->SourceConnectionId;
  1565. Connection->CurrentSend.SendSequence = 1;
  1566. Connection->UnAckedSend.SendSequence = 1;
  1567. Connection->RetransmitThisWindow = FALSE;
  1568. Connection->ReceiveSequence = 0;
  1569. Connection->CurrentReceive.MessageOffset = 0;
  1570. Connection->Retries = NbiDevice->KeepAliveCount;
  1571. if (NbiDevice->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
  1572. Connection->NewNetbios = TRUE;
  1573. Connection->LocalRcvSequenceMax =
  1574. (USHORT)(Connection->ReceiveWindowSize - 1);
  1575. Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
  1576. Connection->SendWindowSequenceLimit = 3;
  1577. } else {
  1578. Connection->NewNetbios = FALSE;
  1579. }
  1580. if (Connection->MaximumPacketSize > SessInit->MaximumDataSize) {
  1581. Connection->MaximumPacketSize = SessInit->MaximumDataSize;
  1582. }
  1583. Request = Connection->ConnectRequest;
  1584. #ifdef RASAUTODIAL
  1585. //
  1586. // Check to see if we have to notify
  1587. // the automatic connection driver about
  1588. // this connection.
  1589. //
  1590. if (fAcdLoadedG) {
  1591. BOOLEAN fEnabled;
  1592. CTELockHandle AcdHandle;
  1593. CTEGetLock(&AcdDriverG.SpinLock, &AcdHandle);
  1594. fEnabled = AcdDriverG.fEnabled;
  1595. CTEFreeLock(&AcdDriverG.SpinLock, AcdHandle);
  1596. if (fEnabled)
  1597. NbiNoteNewConnection(Connection);
  1598. }
  1599. #endif // RASAUTODIAL
  1600. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1601. NB_GET_CANCEL_LOCK( &CancelLH );
  1602. IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
  1603. NB_FREE_CANCEL_LOCK( CancelLH );
  1604. REQUEST_STATUS (Request) = STATUS_SUCCESS;
  1605. NbiCompleteRequest (Request);
  1606. NbiFreeRequest (Device, Request);
  1607. NbiTransferReferenceConnection (Connection, CREF_CONNECT, CREF_ACTIVE);
  1608. if (TimerWasStopped) {
  1609. NbiDereferenceConnection (Connection, CREF_TIMER);
  1610. }
  1611. } else {
  1612. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1613. }
  1614. } /* NbiProcessSessionInitAck */
  1615. VOID
  1616. NbiProcessSessionEnd(
  1617. IN PIPX_LOCAL_TARGET RemoteAddress,
  1618. IN ULONG MacOptions,
  1619. IN PUCHAR PacketBuffer,
  1620. IN UINT PacketSize
  1621. )
  1622. /*++
  1623. Routine Description:
  1624. This routine handles NB_CMD_SESSION_END frames.
  1625. Arguments:
  1626. RemoteAddress - The local target this packet was received from.
  1627. MacOptions - The MAC options for the underlying NDIS binding.
  1628. LookaheadBuffer - The packet data, starting at the IPX
  1629. header.
  1630. PacketSize - The total length of the packet, starting at the
  1631. IPX header.
  1632. Return Value:
  1633. None.
  1634. --*/
  1635. {
  1636. NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
  1637. NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
  1638. PCONNECTION Connection;
  1639. PDEVICE Device = NbiDevice;
  1640. ULONG Hash;
  1641. NB_DEFINE_LOCK_HANDLE (LockHandle1)
  1642. NB_DEFINE_LOCK_HANDLE (LockHandle2)
  1643. //
  1644. // This is an active connection, find it using
  1645. // our session id.
  1646. //
  1647. Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
  1648. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
  1649. Connection = Device->ConnectionHash[Hash].Connections;
  1650. while (Connection != NULL) {
  1651. if (Connection->LocalConnectionId == Sess->DestConnectionId) {
  1652. break;
  1653. }
  1654. Connection = Connection->NextConnection;
  1655. }
  1656. //
  1657. // We reply to any session end, even if we don't know the
  1658. // connection, to speed up the disconnect on the remote.
  1659. //
  1660. if (Connection == NULL) {
  1661. NB_DEBUG (CONNECTION, ("Session end received on unknown id %lx\n", Sess->DestConnectionId));
  1662. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1663. NbiSendSessionEndAck(
  1664. (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
  1665. RemoteAddress,
  1666. Sess);
  1667. return;
  1668. }
  1669. NbiReferenceConnectionLock (Connection, CREF_INDICATE);
  1670. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1671. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
  1672. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
  1673. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  1674. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1675. if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
  1676. //
  1677. // We are waiting for an ack, so see if this acks
  1678. // anything. We do this in case a full send has been
  1679. // received by the remote but he did not send an
  1680. // ack before the session went down -- this will
  1681. // prevent us from failing a send which actually
  1682. // succeeded. If we are not in W_ACK this may ack
  1683. // part of a send, but in that case we don't care
  1684. // since StopConnection will abort it anyway and
  1685. // the amount successfully received by the remote
  1686. // doesn't matter.
  1687. //
  1688. // This releases the lock.
  1689. //
  1690. NB_DEBUG2 (CONNECTION, ("Session end at W_ACK, reframing %lx (%d)\n", Connection, Sess->ReceiveSequence));
  1691. NbiReframeConnection(
  1692. Connection,
  1693. Sess->ReceiveSequence,
  1694. Sess->BytesReceived,
  1695. FALSE
  1696. NB_LOCK_HANDLE_ARG(LockHandle1));
  1697. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
  1698. } else {
  1699. NB_DEBUG2 (CONNECTION, ("Session end received on connection %lx\n", Connection));
  1700. }
  1701. //
  1702. // This call sets the state to DISCONNECT and
  1703. // releases the connection lock. It will also
  1704. // complete a disconnect wait request if one
  1705. // is pending, and indicate to our client
  1706. // if needed.
  1707. //
  1708. NbiStopConnection(
  1709. Connection,
  1710. STATUS_REMOTE_DISCONNECT
  1711. NB_LOCK_HANDLE_ARG (LockHandle1));
  1712. } else {
  1713. NB_DEBUG2 (CONNECTION, ("Session end received on inactive connection %lx\n", Connection));
  1714. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1715. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  1716. }
  1717. NbiSendSessionEndAck(
  1718. (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
  1719. RemoteAddress,
  1720. Sess);
  1721. NbiDereferenceConnection (Connection, CREF_INDICATE);
  1722. } /* NbiProcessSessionEnd */
  1723. VOID
  1724. NbiProcessSessionEndAck(
  1725. IN PIPX_LOCAL_TARGET RemoteAddress,
  1726. IN ULONG MacOptions,
  1727. IN PUCHAR PacketBuffer,
  1728. IN UINT PacketSize
  1729. )
  1730. /*++
  1731. Routine Description:
  1732. This routine handles NB_CMD_SESSION_END_ACK frames.
  1733. Arguments:
  1734. RemoteAddress - The local target this packet was received from.
  1735. MacOptions - The MAC options for the underlying NDIS binding.
  1736. LookaheadBuffer - The packet data, starting at the IPX
  1737. header.
  1738. PacketSize - The total length of the packet, starting at the
  1739. IPX header.
  1740. Return Value:
  1741. None.
  1742. --*/
  1743. {
  1744. NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
  1745. NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
  1746. PCONNECTION Connection;
  1747. PDEVICE Device = NbiDevice;
  1748. ULONG Hash;
  1749. NB_DEFINE_LOCK_HANDLE (LockHandle)
  1750. //
  1751. // This is an active connection, find it using
  1752. // our session id.
  1753. //
  1754. Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
  1755. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  1756. Connection = Device->ConnectionHash[Hash].Connections;
  1757. while (Connection != NULL) {
  1758. if (Connection->LocalConnectionId == Sess->DestConnectionId) {
  1759. break;
  1760. }
  1761. Connection = Connection->NextConnection;
  1762. }
  1763. if (Connection == NULL) {
  1764. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1765. return;
  1766. }
  1767. NbiReferenceConnectionLock (Connection, CREF_INDICATE);
  1768. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1769. //
  1770. // See what is happening with this connection.
  1771. //
  1772. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  1773. if (Connection->State == CONNECTION_STATE_DISCONNECT) {
  1774. //
  1775. // Stop the timer, when the reference goes away it
  1776. // will shut down. We set the substate so if the
  1777. // timer is running it will not restart (there is
  1778. // a small window here, but it is not
  1779. // harmful, we will just have to timeout one
  1780. // more time).
  1781. //
  1782. NB_DEBUG2 (CONNECTION, ("Got session end ack on %lx\n", Connection));
  1783. Connection->SubState = CONNECTION_SUBSTATE_D_GOT_ACK;
  1784. if (CTEStopTimer (&Connection->Timer)) {
  1785. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1786. NbiDereferenceConnection (Connection, CREF_TIMER);
  1787. } else {
  1788. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1789. }
  1790. } else {
  1791. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1792. }
  1793. NbiDereferenceConnection (Connection, CREF_INDICATE);
  1794. } /* NbiProcessSessionEndAck */