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.

6521 lines
215 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Tdihndlr.c
  5. Abstract:
  6. This file contains the TDI handlers that are setup for Connects,
  7. Receives, Disconnects, and Errors on various objects such as connections
  8. and udp endpoints .
  9. This file represents the inbound TDI interface on the Bottom of NBT. Therefore
  10. the code basically decodes the incoming information and passes it to
  11. a non-Os specific routine to do what it can. Upon return from that
  12. routine additional Os specific work may need to be done.
  13. Author:
  14. Jim Stewart (Jimst) 10-2-92
  15. Revision History:
  16. Will Lees (wlees) Sep 11, 1997
  17. Added support for message-only devices
  18. --*/
  19. #include "precomp.h"
  20. #include "ctemacro.h"
  21. #include "tdihndlr.tmh"
  22. // this macro checks that the types field is always zero in the Session
  23. // Pdu
  24. //
  25. #if DBG
  26. #define CHECK_PDU( _Size,_Offset) \
  27. if (_Size > 1) \
  28. ASSERT(((PUCHAR)pTsdu)[_Offset] == 0)
  29. #else
  30. #define CHECK_PDU( _Size,_Offset )
  31. #endif
  32. #if DBG
  33. UCHAR pLocBuff[256];
  34. UCHAR CurrLoc;
  35. ULONG R1;
  36. ULONG R2;
  37. ULONG R3;
  38. ULONG R4;
  39. ULONG C1;
  40. ULONG C2;
  41. ULONG C3;
  42. ULONG C4;
  43. ULONG HitCounter;
  44. #define INCR_COUNT(_Count) _Count++
  45. #else
  46. #define INCR_COUNT(_Count)
  47. #endif
  48. //
  49. // This ntohl swaps just three bytes, since the 4th byte could be a session
  50. // keep alive message type.
  51. //
  52. __inline long
  53. myntohl(long x)
  54. {
  55. return((((x) >> 24) & 0x000000FFL) |
  56. (((x) >> 8) & 0x0000FF00L) |
  57. (((x) << 8) & 0x00FF0000L));
  58. }
  59. NTSTATUS
  60. LessThan4BytesRcvd(
  61. IN tLOWERCONNECTION *pLowerConn,
  62. IN ULONG BytesAvailable,
  63. OUT PULONG BytesTaken,
  64. OUT PVOID *ppIrp
  65. );
  66. NTSTATUS
  67. ClientTookSomeOfTheData(
  68. IN tLOWERCONNECTION *pLowerConn,
  69. IN ULONG BytesIndicated,
  70. IN ULONG BytesAvailable,
  71. IN ULONG BytesTaken,
  72. IN ULONG PduSize
  73. );
  74. NTSTATUS
  75. MoreDataRcvdThanNeeded(
  76. IN tLOWERCONNECTION *pLowerConn,
  77. IN ULONG BytesIndicated,
  78. IN ULONG BytesAvailable,
  79. OUT PULONG BytesTaken,
  80. IN PVOID pTsdu,
  81. OUT PVOID *ppIrp
  82. );
  83. NTSTATUS
  84. NotEnoughDataYet(
  85. IN tLOWERCONNECTION *pLowerConn,
  86. IN ULONG BytesIndicated,
  87. IN ULONG BytesAvailable,
  88. OUT PULONG BytesTaken,
  89. IN ULONG PduSize,
  90. OUT PVOID *ppIrp
  91. );
  92. NTSTATUS
  93. ProcessIrp(
  94. IN tLOWERCONNECTION *pLowerConn,
  95. IN PIRP pIrp,
  96. IN PVOID pBuffer,
  97. IN PULONG BytesTaken,
  98. IN ULONG BytesIndicted,
  99. IN ULONG BytesAvailable
  100. );
  101. NTSTATUS
  102. NtBuildIndicateForReceive (
  103. IN tLOWERCONNECTION *pLowerConn,
  104. IN ULONG Length,
  105. OUT PVOID *ppIrp
  106. );
  107. NTSTATUS
  108. AcceptCompletionRoutine(
  109. IN PDEVICE_OBJECT DeviceObject,
  110. IN PIRP pIrp,
  111. IN PVOID pContext
  112. );
  113. VOID
  114. DpcNextOutOfRsrcKill(
  115. IN PKDPC pDpc,
  116. IN PVOID Context,
  117. IN PVOID SystemArgument1,
  118. IN PVOID SystemArgument2
  119. );
  120. VOID
  121. DpcGetRestOfIndication(
  122. IN PKDPC pDpc,
  123. IN PVOID Context,
  124. IN PVOID SystemArgument1,
  125. IN PVOID SystemArgument2
  126. );
  127. NTSTATUS
  128. ClientBufferOverFlow(
  129. IN tLOWERCONNECTION *pLowerConn,
  130. IN tCONNECTELE *pConnEle,
  131. IN PIRP pIrp,
  132. IN ULONG BytesRcvd
  133. );
  134. VOID
  135. DpcHandleNewSessionPdu (
  136. IN PKDPC pDpc,
  137. IN PVOID Context,
  138. IN PVOID SystemArgument1,
  139. IN PVOID SystemArgument2
  140. );
  141. VOID
  142. HandleNewSessionPdu (
  143. IN tLOWERCONNECTION *pLowerConn,
  144. IN ULONG Offset,
  145. IN ULONG ToGet
  146. );
  147. NTSTATUS
  148. NewSessionCompletionRoutine (
  149. IN PDEVICE_OBJECT DeviceObject,
  150. IN PIRP pIrp,
  151. IN PVOID pContext
  152. );
  153. NTSTATUS
  154. BuildIrpForNewSessionInIndication (
  155. IN tLOWERCONNECTION *pLowerConn,
  156. IN PIRP pIrpIn,
  157. IN ULONG BytesAvailable,
  158. IN ULONG RemainingPdu,
  159. OUT PIRP *ppIrp
  160. );
  161. VOID
  162. TrackIndicatedBytes(
  163. IN ULONG BytesIndicated,
  164. IN ULONG BytesTaken,
  165. IN tCONNECTELE *pConnEle
  166. );
  167. __inline
  168. VOID
  169. DerefLowerConnFast (
  170. IN tLOWERCONNECTION *pLowerConn,
  171. IN CTELockHandle OldIrq
  172. );
  173. NTSTATUS
  174. CopyDataandIndicate(
  175. IN PVOID ReceiveEventContext,
  176. IN PVOID ConnectionContext,
  177. IN USHORT ReceiveFlags,
  178. IN ULONG BytesIndicated,
  179. IN ULONG BytesAvailable,
  180. OUT PULONG BytesTaken,
  181. IN PVOID pTsdu,
  182. OUT PIRP *ppIrp
  183. );
  184. VOID
  185. SumMdlLengths (
  186. IN PMDL pMdl,
  187. IN ULONG BytesAvailable,
  188. IN tCONNECTELE *pConnectEle
  189. );
  190. NTSTATUS
  191. RsrcKillCompletion(
  192. IN PDEVICE_OBJECT DeviceObject,
  193. IN PIRP pIrp,
  194. IN PVOID pContext
  195. );
  196. VOID
  197. NbtCancelFillIrpRoutine(
  198. IN PDEVICE_OBJECT DeviceContext,
  199. IN PIRP pIrp
  200. );
  201. NTSTATUS
  202. NameSrvCompletionRoutine(
  203. IN PDEVICE_OBJECT DeviceObject,
  204. IN PIRP Irp,
  205. IN PVOID Context
  206. );
  207. #ifdef _NETBIOSLESS
  208. NTSTATUS
  209. PerformInboundProcessing(
  210. tDEVICECONTEXT *pDeviceContext,
  211. tLOWERCONNECTION *pLowerConn,
  212. PTA_IP_ADDRESS pIpAddress
  213. );
  214. #endif
  215. //----------------------------------------------------------------------------
  216. __inline
  217. NTSTATUS
  218. Normal(
  219. IN PVOID ReceiveEventContext,
  220. IN tLOWERCONNECTION *pLowerConn,
  221. IN USHORT ReceiveFlags,
  222. IN ULONG BytesIndicated,
  223. IN ULONG BytesAvailable,
  224. OUT PULONG BytesTaken,
  225. IN PVOID pTsdu,
  226. OUT PVOID *ppIrp
  227. )
  228. /*++
  229. Routine Description:
  230. This routine is the receive event indication handler.
  231. It is called when an session packet arrives from the network. It calls
  232. a non OS specific routine to decide what to do. That routine passes back
  233. either a RcvElement (buffer) or a client rcv handler to call.
  234. Arguments:
  235. Return Value:
  236. NTSTATUS - Status of receive operation
  237. --*/
  238. {
  239. ASSERTMSG("Should not execute this procedure",0);
  240. return(STATUS_SUCCESS);
  241. }
  242. //----------------------------------------------------------------------------
  243. NTSTATUS
  244. LessThan4BytesRcvd(
  245. IN tLOWERCONNECTION *pLowerConn,
  246. IN ULONG BytesAvailable,
  247. OUT PULONG BytesTaken,
  248. OUT PVOID *ppIrp
  249. )
  250. /*++
  251. Routine Description:
  252. This routine handles the case when data has arrived on a connection but
  253. there isn't 128 bytes yet or a whole pdu.
  254. Arguments:
  255. Return Value:
  256. NTSTATUS - Status of receive operation
  257. --*/
  258. {
  259. tCONNECTELE *pConnectEle;
  260. NTSTATUS status;
  261. // for short indications less than 4 bytes we can't determine
  262. // the pdu size so just get the header first then get the
  263. // whole pdu next.
  264. status = NtBuildIrpForReceive(pLowerConn,
  265. sizeof(tSESSIONHDR),
  266. (PVOID *)ppIrp);
  267. pConnectEle = pLowerConn->pUpperConnection;
  268. pConnectEle->BytesInXport = BytesAvailable;
  269. if (!NT_SUCCESS(status))
  270. {
  271. CTESpinFreeAtDpc(pLowerConn);
  272. OutOfRsrcKill(pLowerConn);
  273. CTESpinLockAtDpc(pLowerConn);
  274. return( STATUS_DATA_NOT_ACCEPTED);
  275. }
  276. //
  277. // set the irp mdl length to size of session hdr so that
  278. // we don't get more than one session pdu into the buffer
  279. //
  280. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  281. *BytesTaken = 0;
  282. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  283. KdPrint(("Nbt:Switching to Ind Buff(<4 bytes), Avail = %X\n",
  284. BytesAvailable));
  285. PUSH_LOCATION(0);
  286. return(STATUS_MORE_PROCESSING_REQUIRED);
  287. }
  288. //----------------------------------------------------------------------------
  289. NTSTATUS
  290. ClientTookSomeOfTheData(
  291. IN tLOWERCONNECTION *pLowerConn,
  292. IN ULONG BytesIndicated,
  293. IN ULONG BytesAvailable,
  294. IN ULONG BytesTaken,
  295. IN ULONG PduSize
  296. )
  297. /*++
  298. Routine Description:
  299. This routine handles the case when data has arrived on a connection but
  300. the client has not taken all of the data indicated to it.
  301. Arguments:
  302. Return Value:
  303. NTSTATUS - Status of receive operation
  304. --*/
  305. {
  306. tCONNECTELE *pConnectEle;
  307. //
  308. // took some of the data, so keep track of the
  309. // rest of the data left here by going to the PARTIALRCV
  310. // state.
  311. //
  312. PUSH_LOCATION(0x5);
  313. SET_STATERCV_LOWER(pLowerConn, PARTIAL_RCV, PartialRcv);
  314. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  315. KdPrint(("Nbt.ClientTookSomeOfTheData: Switch to Partial Rcv Indicated=%X, PduSize=%X\n",
  316. BytesIndicated,PduSize-4));
  317. // Note: PduSize must include the 4 byte session header for this to
  318. // work correctly.
  319. //
  320. pConnectEle = pLowerConn->pUpperConnection;
  321. //
  322. // We always indicate the whole Pdu size to the client, so the amount
  323. // indicated is that minus what was taken - typically the 4 byte
  324. // session hdr
  325. //
  326. pConnectEle->ReceiveIndicated = PduSize - BytesTaken;
  327. // amount left in the transport...
  328. pConnectEle->BytesInXport = BytesAvailable - BytesTaken;
  329. // need to return this status since we took the 4 bytes
  330. // session header at least, even if the client took none.
  331. return(STATUS_SUCCESS);
  332. }
  333. //----------------------------------------------------------------------------
  334. NTSTATUS
  335. MoreDataRcvdThanNeeded(
  336. IN tLOWERCONNECTION *pLowerConn,
  337. IN ULONG BytesIndicated,
  338. IN ULONG BytesAvailable,
  339. OUT PULONG BytesTaken,
  340. IN PVOID pTsdu,
  341. OUT PVOID *ppIrp
  342. )
  343. /*++
  344. Routine Description:
  345. This routine handles the case when data has arrived on a connection but
  346. there isn't 128 bytes yet or a whole pdu.
  347. Arguments:
  348. Return Value:
  349. NTSTATUS - Status of receive operation
  350. --*/
  351. {
  352. tCONNECTELE *pConnectEle;
  353. ULONG Length;
  354. ULONG Remaining;
  355. ULONG PduSize;
  356. NTSTATUS status;
  357. tSESSIONHDR UNALIGNED *pSessionHdr;
  358. PUSH_LOCATION(0x6);
  359. //
  360. // there is too much data, so keep track of the
  361. // fact that there is data left in the transport
  362. // and get it with the indicate buffer
  363. //
  364. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  365. ASSERT(pLowerConn->BytesInIndicate == 0);
  366. #if DBG
  367. if (pLowerConn->BytesInIndicate)
  368. {
  369. KdPrint(("Nbt:Bytes in indicate should be ZERO, but are = %X\n",
  370. pLowerConn->BytesInIndicate));
  371. }
  372. #endif
  373. pConnectEle = pLowerConn->pUpperConnection;
  374. pConnectEle->BytesInXport = BytesAvailable - *BytesTaken;
  375. //
  376. // for short indications less than 4 bytes we can't determine
  377. // the pdu size so just get the header first then get the
  378. // whole pdu next.
  379. //
  380. Remaining = BytesIndicated - *BytesTaken;
  381. if ((LONG) Remaining < (LONG) sizeof(tSESSIONHDR))
  382. {
  383. status = NtBuildIrpForReceive(pLowerConn,sizeof(tSESSIONHDR),(PVOID *)ppIrp);
  384. if (!NT_SUCCESS(status))
  385. {
  386. // this is a serious error - we must
  387. // kill of the connection and let the
  388. // redirector restart it
  389. KdPrint(("Nbt:Unable to get an Irp for RCv - Closing Connection!! %X\n",pLowerConn));
  390. CTESpinFreeAtDpc(pLowerConn);
  391. OutOfRsrcKill(pLowerConn);
  392. CTESpinLockAtDpc(pLowerConn);
  393. return(STATUS_DATA_NOT_ACCEPTED);
  394. }
  395. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  396. KdPrint(("Nbt:< 4 Bytes,BytesTaken=%X,Avail=%X,Ind=%X,Remain=%X\n",
  397. *BytesTaken,BytesAvailable,BytesIndicated,
  398. Remaining));
  399. // DEBUG
  400. CTEZeroMemory(MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl),
  401. NBT_INDICATE_BUFFER_SIZE);
  402. PUSH_LOCATION(0x7);
  403. status = STATUS_MORE_PROCESSING_REQUIRED;
  404. }
  405. else
  406. {
  407. // if we get to here there are enough bytes left to determine
  408. // the next pdu size...so we can determine how much
  409. // data to get for the indicate buffer
  410. //
  411. pSessionHdr = (tSESSIONHDR UNALIGNED *)((PUCHAR)pTsdu + *BytesTaken);
  412. PduSize = myntohl(pSessionHdr->UlongLength) + sizeof(tSESSIONHDR);
  413. Length = (PduSize > NBT_INDICATE_BUFFER_SIZE) ?
  414. NBT_INDICATE_BUFFER_SIZE : PduSize;
  415. //
  416. // The NewSessionCompletion routine recalculates
  417. // what is left in the transport when the
  418. // irp completes
  419. //
  420. status = NtBuildIrpForReceive(pLowerConn,Length,(PVOID *)ppIrp);
  421. if (!NT_SUCCESS(status))
  422. {
  423. // this is a serious error - we must
  424. // kill of the connection and let the
  425. // redirector restart it
  426. KdPrint(("Nbt:Unable to get an Irp for RCV(2) - Closing Connection!! %X\n",pLowerConn));
  427. CTESpinFreeAtDpc(pLowerConn);
  428. OutOfRsrcKill(pLowerConn);
  429. CTESpinLockAtDpc(pLowerConn);
  430. return(STATUS_DATA_NOT_ACCEPTED);
  431. }
  432. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  433. KdPrint(("Nbt:Switch to Ind Buff, InXport = %X, Pdusize=%X,ToGet=%X\n",
  434. pConnectEle->BytesInXport,PduSize-4,Length));
  435. }
  436. return(STATUS_MORE_PROCESSING_REQUIRED);
  437. }
  438. //----------------------------------------------------------------------------
  439. NTSTATUS
  440. NotEnoughDataYet(
  441. IN tLOWERCONNECTION *pLowerConn,
  442. IN ULONG BytesIndicated,
  443. IN ULONG BytesAvailable,
  444. OUT PULONG BytesTaken,
  445. IN ULONG PduSize,
  446. OUT PVOID *ppIrp
  447. )
  448. /*++
  449. Routine Description:
  450. This routine handles the case when data has arrived on a connection but
  451. there isn't 128 bytes yet or a whole pdu.
  452. Arguments:
  453. Return Value:
  454. NTSTATUS - Status of receive operation
  455. --*/
  456. {
  457. NTSTATUS status;
  458. tCONNECTELE *pConnectEle;
  459. ULONG Length;
  460. PUSH_LOCATION(0x9);
  461. //
  462. // not enough data indicated, so use the indicate buffer
  463. //
  464. Length = (PduSize > NBT_INDICATE_BUFFER_SIZE) ?
  465. NBT_INDICATE_BUFFER_SIZE : PduSize;
  466. status = NtBuildIrpForReceive(pLowerConn,Length,(PVOID *)ppIrp);
  467. if (!NT_SUCCESS(status))
  468. {
  469. CTESpinFreeAtDpc(pLowerConn);
  470. OutOfRsrcKill(pLowerConn);
  471. CTESpinLockAtDpc(pLowerConn);
  472. return(STATUS_DATA_NOT_ACCEPTED);
  473. }
  474. *BytesTaken = 0;
  475. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  476. pConnectEle = pLowerConn->pUpperConnection;
  477. pConnectEle->BytesInXport = BytesAvailable;
  478. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  479. KdPrint(("Nbt:Not Enough data indicated in Tdihndlr, using indic. buffer Indicated = %X,Avail=%X,PduSize= %X\n",
  480. BytesIndicated, BytesAvailable,PduSize-4));
  481. return(STATUS_MORE_PROCESSING_REQUIRED);
  482. }
  483. //----------------------------------------------------------------------------
  484. NTSTATUS
  485. FillIrp(
  486. IN PVOID ReceiveEventContext,
  487. IN tLOWERCONNECTION *pLowerConn,
  488. IN USHORT ReceiveFlags,
  489. IN ULONG BytesIndicated,
  490. IN ULONG BytesAvailable,
  491. OUT PULONG BytesTaken,
  492. IN PVOID pTsdu,
  493. OUT PVOID *ppIrp
  494. )
  495. /*++
  496. Routine Description:
  497. This routine is the receive event indication handler.
  498. It is called when an session packet arrives from the network. It calls
  499. a non OS specific routine to decide what to do. That routine passes back
  500. either a RcvElement (buffer) or a client rcv handler to call.
  501. Arguments:
  502. Return Value:
  503. NTSTATUS - Status of receive operation
  504. --*/
  505. {
  506. ASSERTMSG("Should not execute this procedure",0);
  507. return(STATUS_SUCCESS);
  508. // do nothing
  509. }
  510. //----------------------------------------------------------------------------
  511. NTSTATUS
  512. IndicateBuffer(
  513. IN PVOID ReceiveEventContext,
  514. IN tLOWERCONNECTION *pLowerConn,
  515. IN USHORT ReceiveFlags,
  516. IN ULONG BytesIndicated,
  517. IN ULONG BytesAvailable,
  518. OUT PULONG BytesTaken,
  519. IN PVOID pTsdu,
  520. OUT PVOID *ppIrp
  521. )
  522. /*++
  523. Routine Description:
  524. This routine handles reception of data while in the IndicateBuffer state.
  525. In this state the indicate buffer is receiveing data until at least
  526. 128 bytes have been receive, or a whole pdu has been received.
  527. Arguments:
  528. Return Value:
  529. NTSTATUS - Status of receive operation
  530. --*/
  531. {
  532. tCONNECTELE *pConnectEle;
  533. NTSTATUS status;
  534. ULONG PduSize;
  535. ULONG ToCopy;
  536. PVOID pIndicateBuffer;
  537. ULONG Taken;
  538. //
  539. // there is data in the indicate buffer and we got a new
  540. // indication, so copy some or all of the indication to the
  541. // indicate buffer
  542. //
  543. PVOID pDest;
  544. ULONG RemainPdu;
  545. ULONG SpaceLeft;
  546. ULONG TotalBytes;
  547. ULONG ToCopy1=0;
  548. INCR_COUNT(R3);
  549. PUSH_LOCATION(0xe);
  550. pConnectEle = pLowerConn->pUpperConnection;
  551. ASSERT(pLowerConn->StateRcv == INDICATE_BUFFER);
  552. //
  553. // The indicate buffer always starts with a pdu
  554. //
  555. pIndicateBuffer = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
  556. // the location to start copying the new data into is right
  557. // after the existing data in the buffer
  558. //
  559. pDest = (PVOID)((PUCHAR)pIndicateBuffer + pLowerConn->BytesInIndicate);
  560. //
  561. // the session header may not be all into the indicate
  562. // buffer yet, so check that before getting the pdu length.
  563. //
  564. if (pLowerConn->BytesInIndicate < sizeof(tSESSIONHDR))
  565. {
  566. PUSH_LOCATION(0xe);
  567. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  568. KdPrint(("Nbt:Too Few in Indicate Buff, Adding InIndicate %X\n",
  569. pLowerConn->BytesInIndicate));
  570. ToCopy1 = sizeof(tSESSIONHDR) - pLowerConn->BytesInIndicate;
  571. if (ToCopy1 > BytesIndicated)
  572. {
  573. ToCopy1 = BytesIndicated;
  574. }
  575. CTEMemCopy(pDest,pTsdu,ToCopy1);
  576. pDest = (PVOID)((PUCHAR)pDest + ToCopy1);
  577. pTsdu = (PVOID)((PUCHAR)pTsdu + ToCopy1);
  578. pLowerConn->BytesInIndicate += (USHORT)ToCopy1;
  579. *BytesTaken = ToCopy1;
  580. }
  581. // now check again, and pass down an irp to get more data if necessary
  582. //
  583. if (pLowerConn->BytesInIndicate < sizeof(tSESSIONHDR))
  584. {
  585. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  586. KdPrint(("Nbt:< 4 Bytes in IndicBuff, BytesinInd= %X, BytesIndicated=%x\n",
  587. pLowerConn->BytesInIndicate,BytesIndicated));
  588. PUSH_LOCATION(0xF);
  589. //
  590. // the data left in the transport is what was Available
  591. // minus what we just copied to the indicate buffer
  592. //
  593. pConnectEle->BytesInXport = BytesAvailable - ToCopy1;
  594. if (pConnectEle->BytesInXport)
  595. {
  596. PUSH_LOCATION(0x10);
  597. //
  598. // pass the indicate buffer down to get some more data
  599. // to fill out to the end of the session hdr
  600. //
  601. NtBuildIndicateForReceive(pLowerConn,
  602. sizeof(tSESSIONHDR)-pLowerConn->BytesInIndicate,
  603. (PVOID *)ppIrp);
  604. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  605. KdPrint(("Nbt:INDIC_BUF...need more data for hdr Avail= %X, InXport = %X\n",
  606. BytesAvailable,pConnectEle->BytesInXport,pLowerConn));
  607. return(STATUS_MORE_PROCESSING_REQUIRED);
  608. }
  609. // if we get to here there isn't 4 bytes in the indicate buffer and
  610. // there is no more data in the Transport, so just wait for the next
  611. // indication.
  612. //
  613. return(STATUS_SUCCESS);
  614. }
  615. PduSize = myntohl(((tSESSIONHDR *)pIndicateBuffer)->UlongLength)
  616. + sizeof(tSESSIONHDR);
  617. // copy up to 132 bytes or the whole pdu to the indicate buffer
  618. //
  619. RemainPdu = PduSize - pLowerConn->BytesInIndicate;
  620. SpaceLeft = NBT_INDICATE_BUFFER_SIZE - pLowerConn->BytesInIndicate;
  621. if (RemainPdu < SpaceLeft)
  622. ToCopy = RemainPdu;
  623. else
  624. ToCopy = SpaceLeft;
  625. if (ToCopy > (BytesIndicated-ToCopy1))
  626. {
  627. ToCopy = (BytesIndicated - ToCopy1);
  628. }
  629. //
  630. // Copy the indication or part of it to the indication
  631. // buffer
  632. //
  633. CTEMemCopy(pDest,pTsdu,ToCopy);
  634. pLowerConn->BytesInIndicate += (USHORT)ToCopy;
  635. TotalBytes = pLowerConn->BytesInIndicate;
  636. // the amount of data taken is the amount copied to the
  637. // indicate buffer
  638. //
  639. *BytesTaken = ToCopy + ToCopy1;
  640. #if DBG
  641. {
  642. tSESSIONHDR UNALIGNED *pSessionHdr;
  643. pSessionHdr = (tSESSIONHDR UNALIGNED *)pIndicateBuffer;
  644. ASSERT((pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE) ||
  645. (pSessionHdr->Type == NBT_SESSION_MESSAGE));
  646. }
  647. #endif
  648. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  649. KdPrint(("Nbt:INDIC_BUFF, TotalBytes= %X, InIndic=%X, Copied(0/1)= %X %X Avail %X\n",
  650. TotalBytes,pLowerConn->BytesInIndicate,ToCopy,ToCopy1,BytesAvailable));
  651. // the data left in the transport is what was Available
  652. // minus what we just copied to the indicate buffer
  653. //
  654. pConnectEle->BytesInXport = BytesAvailable - *BytesTaken;
  655. // now check if we have a whole pdu or 132 bytes, either way
  656. // enough to indicate to the client.
  657. //
  658. ASSERT(TotalBytes <= NBT_INDICATE_BUFFER_SIZE);
  659. if ((TotalBytes < NBT_INDICATE_BUFFER_SIZE) && (TotalBytes < PduSize) && (pConnectEle->BytesInXport)) {
  660. //
  661. // This could happen if BytesIndicated < BytesAvailable
  662. //
  663. ToCopy = PduSize;
  664. if (ToCopy > NBT_INDICATE_BUFFER_SIZE) {
  665. ToCopy = NBT_INDICATE_BUFFER_SIZE;
  666. }
  667. ASSERT (TotalBytes == pLowerConn->BytesInIndicate);
  668. NtBuildIndicateForReceive(pLowerConn, ToCopy - TotalBytes, (PVOID *)ppIrp);
  669. #if DBG
  670. HitCounter++;
  671. #endif
  672. return(STATUS_MORE_PROCESSING_REQUIRED);
  673. }
  674. if ((TotalBytes == NBT_INDICATE_BUFFER_SIZE) ||
  675. (TotalBytes == PduSize))
  676. {
  677. status = CopyDataandIndicate(
  678. ReceiveEventContext,
  679. (PVOID)pLowerConn,
  680. ReceiveFlags,
  681. TotalBytes,
  682. pConnectEle->BytesInXport + TotalBytes,
  683. &Taken,
  684. pIndicateBuffer,
  685. (PIRP *)ppIrp);
  686. }
  687. else
  688. {
  689. // not enough data in the indicate buffer yet
  690. // NOTE: *BytesTaken should be set correctly above...
  691. // = ToCopy + ToCopy1;
  692. PUSH_LOCATION(0x11);
  693. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  694. KdPrint(("Nbt:Not Enough data indicated(INDICBUFF state), Indicated = %X,PduSize= %X,InIndic=%X\n",
  695. BytesIndicated, PduSize, pLowerConn->BytesInIndicate));
  696. status = STATUS_SUCCESS;
  697. }
  698. return(status);
  699. }
  700. //----------------------------------------------------------------------------
  701. NTSTATUS
  702. PartialRcv(
  703. IN PVOID ReceiveEventContext,
  704. IN tLOWERCONNECTION *pLowerConn,
  705. IN USHORT ReceiveFlags,
  706. IN ULONG BytesIndicated,
  707. IN ULONG BytesAvailable,
  708. OUT PULONG BytesTaken,
  709. IN PVOID pTsdu,
  710. OUT PVOID *ppIrp
  711. )
  712. /*++
  713. Routine Description:
  714. This routine is the receive event indication handler.
  715. It is called when an session packet arrives from the network. It calls
  716. a non OS specific routine to decide what to do. That routine passes back
  717. either a RcvElement (buffer) or a client rcv handler to call.
  718. Arguments:
  719. Return Value:
  720. NTSTATUS - Status of receive operation
  721. --*/
  722. {
  723. tCONNECTELE *pConnectEle;
  724. //
  725. // the data for the client may be in the indicate buffer and
  726. // in this case the transport could indicate us with more data. Therefore
  727. // track the number of bytes available in the transport which
  728. // we will get when the client finally posts a buffer.
  729. // This state could also happen on a zero length Rcv when the
  730. // client does not accept the data, and later posts a rcv
  731. // buffer for the zero length rcv.
  732. //
  733. INCR_COUNT(R4);
  734. PUSH_LOCATION(0x13);
  735. ASSERT(pLowerConn->StateRcv == PARTIAL_RCV);
  736. pConnectEle = pLowerConn->pUpperConnection;
  737. // ASSERT(pConnectEle->BytesInXport == 0);
  738. #if DBG
  739. if (pConnectEle->BytesInXport != 0)
  740. {
  741. KdPrint(("Nbt.PartialRcv: pConnectEle->BytesInXport != 0 Avail %X, InIndicate=%X,InXport %X %X\n",
  742. BytesAvailable,pLowerConn->BytesInIndicate,
  743. pConnectEle->BytesInXport,pLowerConn));
  744. }
  745. #endif // DBG
  746. pConnectEle->BytesInXport = BytesAvailable;
  747. IF_DBG(NBT_DEBUG_NAMESRV)
  748. KdPrint(("Nbt:Got Indicated while in PartialRcv state Avail %X, InIndicate=%X,InXport %X %X\n",
  749. BytesAvailable,pLowerConn->BytesInIndicate,
  750. pConnectEle->BytesInXport,pLowerConn));
  751. *BytesTaken = 0;
  752. return(STATUS_SUCCESS);
  753. }
  754. //----------------------------------------------------------------------------
  755. NTSTATUS
  756. TdiReceiveHandler (
  757. IN PVOID ReceiveEventContext,
  758. IN PVOID ConnectionContext,
  759. IN USHORT ReceiveFlags,
  760. IN ULONG BytesIndicated,
  761. IN ULONG BytesAvailable,
  762. OUT PULONG BytesTaken,
  763. IN PVOID pTsdu,
  764. OUT PIRP *ppIrp
  765. )
  766. /*++
  767. Routine Description:
  768. This routine is the receive event indication handler.
  769. It is called when an session packet arrives from the network. It calls
  770. a non OS specific routine to decide what to do. That routine passes back
  771. either a RcvElement (buffer) or a client rcv handler to call.
  772. Arguments:
  773. IN PVOID ReceiveEventContext - Context provided for this event when event set
  774. IN PVOID ConnectionContext - Connection Context, (pLowerConnection)
  775. IN USHORT ReceiveFlags - Flags describing the message
  776. IN ULONG BytesIndicated - Number of bytes available at indication time
  777. IN ULONG BytesAvailable - Number of bytes available to receive
  778. OUT PULONG BytesTaken - Number of bytes consumed by redirector.
  779. IN PVOID pTsdu - Data from remote machine.
  780. OUT PIRP *ppIrp - I/O request packet filled in if received data
  781. Return Value:
  782. NTSTATUS - Status of receive operation
  783. --*/
  784. {
  785. register tLOWERCONNECTION *pLowerConn;
  786. PIRP pIrp;
  787. CTELockHandle OldIrq;
  788. NTSTATUS status;
  789. tCONNECTELE *pConnEle;
  790. ULONG BTaken;
  791. *ppIrp = NULL;
  792. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  793. // NOTE:
  794. // Access is synchronized through the spin lock on pLowerConn for all
  795. // Session related stuff. This includes the case where the client
  796. // posts another Rcv Buffer in NTReceive. - so there is no need to get the
  797. // pConnEle Spin lock too.
  798. //
  799. CTESpinLock(pLowerConn,OldIrq);
  800. // pLowerConn->InRcvHandler = TRUE;
  801. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  802. // save this on the stack in case we need to dereference it below.
  803. pConnEle = pLowerConn->pUpperConnection;
  804. // call the correct routine depending on the state of the connection
  805. // Normal/FillIrp/PartialRcv/IndicateBuffer/Inbound/OutBound
  806. //
  807. if ((pLowerConn->State == NBT_SESSION_UP) &&
  808. (pLowerConn->StateRcv == FILL_IRP))
  809. {
  810. PIO_STACK_LOCATION pIrpSp;
  811. PMDL pNewMdl;
  812. PFILE_OBJECT pFileObject;
  813. ULONG RemainingPdu;
  814. PVOID NewAddress;
  815. PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
  816. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  817. KIRQL OldIrq2;
  818. ULONG RcvLength;
  819. PUSH_LOCATION(0xa);
  820. pIrp = pConnEle->pIrpRcv;
  821. if (!pIrp)
  822. {
  823. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  824. KdPrint (("Nbt:TdiReceiveHandler: No pIrpRcv for pConnEle=<%x>, pLowerConn=<%d>\n",
  825. pConnEle, pLowerConn));
  826. *BytesTaken = 0;
  827. DerefLowerConnFast(pLowerConn,OldIrq);
  828. return (STATUS_SUCCESS);
  829. }
  830. // we are still waiting for the rest of the session pdu so
  831. // do not call the RcvHandlrNotOs, since we already have the buffer
  832. // to put this data in.
  833. // too much data may have arrived... i.e. part of the next session pdu..
  834. // so check and set the receive length accordingly
  835. //
  836. RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  837. RcvLength = RemainingPdu;
  838. //
  839. // try high runner case first
  840. //
  841. if (BytesAvailable <= RemainingPdu)
  842. {
  843. PUSH_LOCATION(0xb);
  844. //
  845. // if the client buffer is too small to take all of the rest of the
  846. // data, shorten the receive length and keep track of how many
  847. // bytes are left in the transport. ReceiveIndicated should have
  848. // been set when the irp was passed down originally.
  849. //
  850. if (BytesAvailable > pConnEle->FreeBytesInMdl)
  851. {
  852. PUSH_LOCATION(0xb);
  853. RcvLength = pConnEle->FreeBytesInMdl;
  854. pConnEle->BytesInXport = BytesAvailable - RcvLength;
  855. }
  856. if (RcvLength > pConnEle->FreeBytesInMdl) {
  857. ASSERT(BytesAvailable <= pConnEle->FreeBytesInMdl);
  858. RcvLength = pConnEle->FreeBytesInMdl;
  859. pConnEle->BytesInXport = 0;
  860. }
  861. }
  862. else
  863. {
  864. //
  865. // start of session pdu in the middle of the indication
  866. //
  867. PUSH_LOCATION(0xc);
  868. //
  869. // It is possible that the client buffer is too short, so check
  870. // for that case.
  871. //
  872. if (RemainingPdu > pConnEle->FreeBytesInMdl)
  873. {
  874. RcvLength = pConnEle->FreeBytesInMdl;
  875. PUSH_LOCATION(0xd);
  876. }
  877. /* Remember how much data is left in the transport
  878. when this irp passes through the completionrcv routine
  879. it will pass the indication buffer back to the transport
  880. to get at least 4 bytes of header information so we
  881. can determine the next session pdu's size before receiving
  882. it. The trick is to avoid having more than one session
  883. pdu in the buffer at once.
  884. */
  885. pConnEle->BytesInXport = BytesAvailable - RcvLength;
  886. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  887. KdPrint(("Nbt:End of FILL_IRP, found new Pdu BytesInXport=%X\n",
  888. pConnEle->BytesInXport));
  889. }
  890. // if the transport has all of the data it says is available, then
  891. // do the copy here ( if the client buffer is large enough - checked
  892. // by !ReceiveIndicated)
  893. //
  894. if ((BytesAvailable == BytesIndicated) &&
  895. (RcvLength >= BytesIndicated) &&
  896. !pConnEle->ReceiveIndicated)
  897. {
  898. ULONG BytesCopied;
  899. ULONG TotalBytes;
  900. PUSH_LOCATION(0x70);
  901. if (RcvLength > BytesIndicated)
  902. RcvLength = BytesIndicated;
  903. status = TdiCopyBufferToMdl(
  904. pTsdu,
  905. 0,
  906. RcvLength,
  907. pConnEle->pNextMdl,
  908. pConnEle->OffsetFromStart,
  909. &BytesCopied);
  910. //
  911. // if the irp is not yet full, or the free bytes have not
  912. // been exhausted by this copy, then adjust some counts and return
  913. // quickly, otherwise call the completion rcv routine as if the
  914. // irp has completed normally from the transport -
  915. //
  916. TotalBytes = pConnEle->BytesRcvd + BytesCopied;
  917. if ((TotalBytes < pConnEle->TotalPcktLen) &&
  918. (BytesCopied < pConnEle->FreeBytesInMdl))
  919. {
  920. PMDL pMdl;
  921. //
  922. // take the short cut and do not call completion rcv since we
  923. // are still waiting for more data
  924. //
  925. PUSH_LOCATION(0x81);
  926. pConnEle->BytesRcvd += BytesCopied;
  927. pConnEle->FreeBytesInMdl -= BytesCopied;
  928. // clean up the partial mdl.
  929. //
  930. pMdl = pConnEle->pNewMdl;
  931. MmPrepareMdlForReuse(pMdl);
  932. // set where the next rcvd data will start, by setting the pNextMdl and
  933. // offset from start.
  934. //
  935. pMdl = pConnEle->pNextMdl;
  936. if ((BytesCopied + pConnEle->OffsetFromStart) < MmGetMdlByteCount(pMdl))
  937. {
  938. PUSH_LOCATION(0x82);
  939. //
  940. // All of this data will fit into the current Mdl, and
  941. // the next data will start in the same Mdl (if there is more data)
  942. //
  943. pConnEle->OffsetFromStart += BytesCopied;
  944. }
  945. else
  946. {
  947. PUSH_LOCATION(0x83)
  948. SumMdlLengths(pMdl,
  949. pConnEle->OffsetFromStart + BytesCopied,
  950. pConnEle);
  951. }
  952. *BytesTaken = BytesCopied;
  953. status = STATUS_SUCCESS;
  954. IF_DBG(NBT_DEBUG_FASTPATH)
  955. KdPrint(("I"));
  956. goto ExitRoutine;
  957. }
  958. else
  959. {
  960. IF_DBG(NBT_DEBUG_FASTPATH)
  961. KdPrint(("i"));
  962. CTESpinFree(pLowerConn,OldIrq);
  963. //
  964. // the values are set to this so that when Completion Rcv is
  965. // called it will increment the BytesRcvd by BytesCopied.
  966. //
  967. pIrp->IoStatus.Status = STATUS_SUCCESS;
  968. pIrp->IoStatus.Information = BytesCopied;
  969. //
  970. // now call the irp completion routine, shorting out the io
  971. // subsystem - to process the irp
  972. //
  973. status = CompletionRcv(NULL,pIrp,(PVOID)pLowerConn);
  974. //
  975. // complete the irp back to the client if required
  976. //
  977. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  978. {
  979. IoAcquireCancelSpinLock(&OldIrq2);
  980. IoSetCancelRoutine(pIrp,NULL);
  981. IoReleaseCancelSpinLock(OldIrq2);
  982. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  983. }
  984. }
  985. //
  986. // tell the transport we took all the data that we did take.
  987. // Since CompletionRcv has unlocked the spin lock and decremented
  988. // the refcount, return here.
  989. //
  990. *BytesTaken = BytesCopied;
  991. return(STATUS_SUCCESS);
  992. }
  993. else
  994. {
  995. //
  996. // Either BytesIndicated != BytesAvailable or the RcvBuffer
  997. // is too short, so make up an Irp with a partial Mdl and pass it
  998. // to the transport.
  999. //
  1000. PUSH_LOCATION(0x71);
  1001. NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pConnEle->pNextMdl)
  1002. + pConnEle->OffsetFromStart);
  1003. /* create a partial MDL so that the new data is copied after the existing data
  1004. in the MDL. Use the pNextMdl field stored in the pConnEle
  1005. that was set up during the last receive.( since at that time
  1006. we knew the BytesAvailable then). Without this we would have to
  1007. traverse the list of Mdls for each receive.
  1008. 0 for length means map the rest of the buffer
  1009. */
  1010. pNewMdl = pConnEle->pNewMdl;
  1011. if ((MmGetMdlByteCount(pConnEle->pNextMdl) - pConnEle->OffsetFromStart) > MAXUSHORT)
  1012. {
  1013. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,MAXUSHORT);
  1014. }
  1015. else
  1016. {
  1017. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,0);
  1018. }
  1019. //
  1020. // hook the new partial mdl to the front of the MDL chain
  1021. //
  1022. pNewMdl->Next = pConnEle->pNextMdl->Next;
  1023. pIrp->MdlAddress = pNewMdl;
  1024. ASSERT(pNewMdl);
  1025. CHECK_PTR(pConnEle);
  1026. pConnEle->pIrpRcv = NULL;
  1027. IoAcquireCancelSpinLock(&OldIrq2);
  1028. IoSetCancelRoutine(pIrp,NULL);
  1029. IoReleaseCancelSpinLock(OldIrq2);
  1030. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1031. pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1032. /* this code is sped up somewhat by expanding the code here rather than calling
  1033. the TdiBuildReceive macro
  1034. make the next stack location the current one. Normally IoCallDriver
  1035. would do this but we are not going through IoCallDriver here, since the
  1036. Irp is just passed back with RcvIndication.
  1037. */
  1038. ASSERT(pIrp->CurrentLocation > 1);
  1039. IoSetNextIrpStackLocation(pIrp);
  1040. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1041. pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1042. pParams->ReceiveLength = RcvLength;
  1043. pIrpSp->CompletionRoutine = CompletionRcv;
  1044. pIrpSp->Context = (PVOID)pLowerConn;
  1045. /* set flags so the completion routine is always invoked.
  1046. */
  1047. pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
  1048. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1049. pIrpSp->MinorFunction = TDI_RECEIVE;
  1050. pFileObject = pLowerConn->pFileObject;
  1051. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  1052. pIrpSp->FileObject = pFileObject;
  1053. pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pFileObject);
  1054. pParams->ReceiveFlags = pClientParams->ReceiveFlags;
  1055. /*
  1056. pass the Irp back to the transport
  1057. */
  1058. *ppIrp = (PVOID)pIrp;
  1059. *BytesTaken = 0;
  1060. status = STATUS_MORE_PROCESSING_REQUIRED;
  1061. }
  1062. }
  1063. else
  1064. if ((pLowerConn->State == NBT_SESSION_UP) &&
  1065. (pLowerConn->StateRcv == NORMAL))
  1066. {
  1067. ULONG PduSize;
  1068. UCHAR Passit;
  1069. INCR_COUNT(R1);
  1070. /*
  1071. check indication and if less than 1 pdu or 132 bytes then
  1072. copy to the indicate buffer and go to Indic_buffer state
  1073. The while loop allows us to indicate multiple Pdus to the
  1074. client in the event that several indications arrive in one
  1075. indication from the transport
  1076. NOTE:
  1077. It is possible to get an indication that occurs in the middle
  1078. of the pdu if the client took the first indication rather
  1079. than passing an irp back, and thence going to the FILL_IRP
  1080. state. So check if BytesRcvd is zero, meaning that we are
  1081. expecting a new PDU.
  1082. */
  1083. ASSERT(pConnEle->BytesInXport == 0);
  1084. ASSERT(pLowerConn->StateRcv == NORMAL);
  1085. if (pConnEle->BytesRcvd == 0)
  1086. {
  1087. if (BytesIndicated >= sizeof(tSESSIONHDR))
  1088. {
  1089. PduSize = myntohl(((tSESSIONHDR UNALIGNED *)pTsdu)->UlongLength)
  1090. + sizeof(tSESSIONHDR);
  1091. Passit = FALSE;
  1092. }
  1093. else
  1094. {
  1095. status = LessThan4BytesRcvd(pLowerConn,
  1096. BytesAvailable,
  1097. BytesTaken,
  1098. ppIrp);
  1099. goto ExitRoutine;
  1100. }
  1101. }
  1102. else
  1103. {
  1104. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1105. KdPrint(("Nbt:Got rest of PDU in indication BytesInd %X, BytesAvail %X\n",
  1106. BytesIndicated, BytesAvailable));
  1107. /* This is the remaining pdu size
  1108. */
  1109. PduSize = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  1110. /* a flag to pass the if below, since we are passing the
  1111. remaining data of a pdu to the client and we do not have
  1112. to adhere to the 128 bytes restriction.
  1113. */
  1114. PUSH_LOCATION(0x1);
  1115. if (pConnEle->JunkMsgFlag)
  1116. {
  1117. //
  1118. // in this case the client has indicated that it took the
  1119. // entire message on the previous indication, so don't
  1120. // indicate any more to it.
  1121. //
  1122. PUSH_LOCATION(0x1);
  1123. if (BytesAvailable < PduSize)
  1124. {
  1125. BTaken = BytesAvailable;
  1126. }
  1127. else
  1128. {
  1129. BTaken = PduSize;
  1130. }
  1131. pConnEle->BytesRcvd += BTaken;
  1132. if (pConnEle->BytesRcvd == pConnEle->TotalPcktLen)
  1133. {
  1134. PUSH_LOCATION(0x1);
  1135. pConnEle->BytesRcvd = 0; // reset for the next session pdu
  1136. pConnEle->JunkMsgFlag = FALSE;
  1137. }
  1138. status = STATUS_SUCCESS;
  1139. goto SkipIndication;
  1140. }
  1141. Passit = TRUE;
  1142. }
  1143. /*
  1144. be sure that there is at least 132 bytes or a whole pdu
  1145. Since a keep alive has a zero length byte, we check for
  1146. that because the 4 byte session hdr is added to the 0 length
  1147. giving 4, so a 4 byte Keep Alive pdu will pass this test.
  1148. */
  1149. if ((BytesIndicated >= NBT_INDICATE_BUFFER_SIZE) ||
  1150. (BytesIndicated >= PduSize) || Passit )
  1151. {
  1152. PUSH_LOCATION(0x2);
  1153. /*
  1154. // Indicate to the client
  1155. */
  1156. status = RcvHandlrNotOs(
  1157. ReceiveEventContext,
  1158. (PVOID)pLowerConn,
  1159. ReceiveFlags,
  1160. BytesIndicated,
  1161. BytesAvailable,
  1162. &BTaken,
  1163. pTsdu,
  1164. (PVOID)&pIrp
  1165. );
  1166. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  1167. {
  1168. ULONG RemainingPdu;
  1169. PIO_STACK_LOCATION pIrpSp;
  1170. PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
  1171. ASSERT(BTaken <= BytesIndicated);
  1172. RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  1173. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1174. pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1175. // check if we can copy to the client's irp directly - meaning
  1176. // that we have received the whole pdu in this indication and
  1177. // the client's buffer is large enough, and there is no more
  1178. // data in the transport.
  1179. //
  1180. if ((RemainingPdu == (BytesIndicated - BTaken)) &&
  1181. (BytesIndicated == BytesAvailable) &&
  1182. (pClientParams->ReceiveLength >= RemainingPdu) &&
  1183. pIrp->MdlAddress)
  1184. {
  1185. ULONG BytesCopied;
  1186. PUSH_LOCATION(0x88);
  1187. status = TdiCopyBufferToMdl(
  1188. (PVOID)((PUCHAR)pTsdu + BTaken),
  1189. 0,
  1190. RemainingPdu,
  1191. pIrp->MdlAddress,
  1192. 0,
  1193. &BytesCopied);
  1194. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1195. KdPrint(("Nbt:Copy to client Buffer RcvLen=%X,StateRcv=%X\n",
  1196. RemainingPdu,pLowerConn->StateRcv));
  1197. pIrp->IoStatus.Information = BytesCopied;
  1198. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1199. // reset a few things since this pdu has been fully recv'd
  1200. //
  1201. CHECK_PTR(pConnEle);
  1202. pConnEle->BytesRcvd = 0;
  1203. CHECK_PTR(pConnEle);
  1204. pConnEle->pIrpRcv = NULL;
  1205. //
  1206. // tell the transport we took all the data that we did take.
  1207. //
  1208. *BytesTaken = BytesCopied + BTaken;
  1209. //
  1210. // complete the irp back to the client if required
  1211. //
  1212. IF_DBG(NBT_DEBUG_FASTPATH)
  1213. KdPrint(("F"));
  1214. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  1215. pLowerConn->BytesRcvd += BytesCopied;
  1216. DerefLowerConnFast(pLowerConn,OldIrq);
  1217. return(STATUS_SUCCESS);
  1218. }
  1219. else
  1220. {
  1221. PUSH_LOCATION(0x3);
  1222. status = ProcessIrp(pLowerConn,
  1223. pIrp,
  1224. pTsdu,
  1225. &BTaken,
  1226. BytesIndicated,
  1227. BytesAvailable);
  1228. *BytesTaken = BTaken;
  1229. ASSERT(*BytesTaken <= (pConnEle->TotalPcktLen + sizeof(tSESSIONHDR)) );
  1230. if (status == STATUS_RECEIVE_EXPEDITED)
  1231. {
  1232. // in this case the processirp routine has completed the
  1233. // irp, so just return since the completion routine will
  1234. // have adjusted the RefCount and InRcvHandler flag
  1235. //
  1236. *ppIrp = NULL;
  1237. CTESpinFree(pLowerConn,OldIrq);
  1238. return(STATUS_SUCCESS);
  1239. }
  1240. else
  1241. if (status == STATUS_SUCCESS)
  1242. {
  1243. *ppIrp = NULL;
  1244. }
  1245. else
  1246. {
  1247. *ppIrp = (PVOID)pIrp;
  1248. }
  1249. }
  1250. }
  1251. else
  1252. {
  1253. // for the skip indication case the client has told us it
  1254. // does not want to be indicated with any more of the data
  1255. //
  1256. SkipIndication:
  1257. //
  1258. // the client received some, all or none of the data
  1259. // For Keep Alives the PduSize is 4 and BytesTaken = 4
  1260. // so this check and return status success
  1261. //
  1262. *BytesTaken = BTaken;
  1263. pLowerConn->BytesRcvd += BTaken - sizeof(tSESSIONHDR);
  1264. //
  1265. // if the connection has disonnected, then just return
  1266. //
  1267. if (!pLowerConn->pUpperConnection)
  1268. {
  1269. *BytesTaken = BytesAvailable;
  1270. status = STATUS_SUCCESS;
  1271. }
  1272. else
  1273. if (BTaken > BytesAvailable)
  1274. {
  1275. //
  1276. // in this case the client has taken all of the message
  1277. // which could be larger than the available because
  1278. // we set bytesavail to the message length. So set a flag
  1279. // that tells us to discard the rest of the message as
  1280. // it comes in.
  1281. //
  1282. pConnEle->JunkMsgFlag = TRUE;
  1283. pConnEle->BytesRcvd = BytesAvailable - sizeof(tSESSIONHDR);
  1284. *BytesTaken = BytesAvailable;
  1285. }
  1286. else
  1287. if (pLowerConn->StateRcv == PARTIAL_RCV)
  1288. {
  1289. // this may be a zero length send -that the client has
  1290. // decided not to accept. If so then the state will be set
  1291. // to PartialRcv. In this case do NOT go down to the transport
  1292. // and get the rest of the data, but wait for the client
  1293. // to post a rcv buffer.
  1294. //
  1295. // amount left in the transport...
  1296. pConnEle->BytesInXport = BytesAvailable - BTaken;
  1297. status = STATUS_SUCCESS;
  1298. }
  1299. else
  1300. if (BTaken == PduSize)
  1301. {
  1302. /*
  1303. Must have taken all of the pdu data, so check for
  1304. more data available - if so send down the indicate
  1305. buffer to get it.
  1306. */
  1307. ASSERT(BTaken <= BytesIndicated);
  1308. if (BytesAvailable <= BTaken)
  1309. {
  1310. /* FAST PATH
  1311. */
  1312. PUSH_LOCATION(0x8);
  1313. status = STATUS_SUCCESS;
  1314. }
  1315. else
  1316. {
  1317. /*
  1318. get remaining data with the indicate buffer
  1319. */
  1320. status = MoreDataRcvdThanNeeded(pLowerConn,
  1321. BytesIndicated,
  1322. BytesAvailable,
  1323. BytesTaken,
  1324. pTsdu,
  1325. ppIrp);
  1326. }
  1327. }
  1328. else
  1329. {
  1330. //
  1331. // the client may have taken all the data in the
  1332. // indication!!, in which case return status success
  1333. // Note: that we check bytes available here not bytes
  1334. // indicated - since the client could take all indicated
  1335. // data but still leave data in the transport.
  1336. //
  1337. if (BTaken == BytesAvailable)
  1338. {
  1339. PUSH_LOCATION(0x4);
  1340. status = STATUS_SUCCESS;
  1341. }
  1342. else
  1343. {
  1344. PUSH_LOCATION(0x87);
  1345. if (BTaken > PduSize)
  1346. {
  1347. #ifndef VXD
  1348. #if DBG
  1349. DbgBreakPoint();
  1350. #endif
  1351. #endif
  1352. //
  1353. // the client took more than a PDU size worth,
  1354. // which is odd....
  1355. //
  1356. PUSH_LOCATION(0x87);
  1357. ASSERT(BTaken <= PduSize);
  1358. CTESpinFreeAtDpc(pLowerConn);
  1359. OutOfRsrcKill(pLowerConn);
  1360. CTESpinLockAtDpc(pLowerConn);
  1361. status = STATUS_SUCCESS;
  1362. }
  1363. else
  1364. {
  1365. //
  1366. // otherwise the client did not take all of the data,
  1367. // which can mean that
  1368. // the client did not take all that it could, so
  1369. // go to the partial rcv state to keep track of it.
  1370. //
  1371. status = ClientTookSomeOfTheData(pLowerConn,
  1372. BytesIndicated,
  1373. BytesAvailable,
  1374. *BytesTaken,
  1375. PduSize);
  1376. }
  1377. }
  1378. }
  1379. }
  1380. }
  1381. else
  1382. {
  1383. status = NotEnoughDataYet(pLowerConn,
  1384. BytesIndicated,
  1385. BytesAvailable,
  1386. BytesTaken,
  1387. PduSize,
  1388. (PVOID *)ppIrp);
  1389. }
  1390. }
  1391. else
  1392. {
  1393. status = (*pLowerConn->CurrentStateProc)(ReceiveEventContext,
  1394. pLowerConn,
  1395. ReceiveFlags,
  1396. BytesIndicated,
  1397. BytesAvailable,
  1398. BytesTaken,
  1399. pTsdu,
  1400. ppIrp);
  1401. }
  1402. //
  1403. // in the IndicateBuffer state we have sent the indicate buffer
  1404. // down the the transport and expect it to come back in
  1405. // NewSessionCompletionRoutine. Therefore do not dereference the lower
  1406. // connection and do not change the InRcvHandler flag.
  1407. // If an Irp
  1408. // is returned, then do not undo the reference - but rather
  1409. // wait for CompletionRcv to be called.
  1410. //
  1411. ExitRoutine:
  1412. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  1413. {
  1414. //
  1415. // quickly check if we can just decrement the ref count without calling
  1416. // NBT_DEREFERENCE_LOWERCONN
  1417. //
  1418. PUSH_LOCATION(0x50);
  1419. DerefLowerConnFast (pLowerConn, OldIrq);
  1420. }
  1421. else
  1422. {
  1423. CTESpinFree(pLowerConn,OldIrq);
  1424. }
  1425. return(status);
  1426. }
  1427. //----------------------------------------------------------------------------
  1428. NTSTATUS
  1429. ProcessIrp(
  1430. IN tLOWERCONNECTION *pLowerConn,
  1431. IN PIRP pIrp,
  1432. IN PVOID pBuffer,
  1433. IN PULONG BytesTaken,
  1434. IN ULONG BytesIndicated,
  1435. IN ULONG BytesAvailable
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. This routine handles a Receive Irp that the client has returned on an
  1440. indication. The idea here is to check the Irp's MDL length to be
  1441. sure the pdu fits into the MDL, and also keep track of the situation where
  1442. more than one data is required to fill the pdu.
  1443. Arguments:
  1444. Return Value:
  1445. The final status from the operation (success or an exception).
  1446. --*/
  1447. {
  1448. NTSTATUS status;
  1449. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  1450. PIO_STACK_LOCATION pIrpSp;
  1451. tCONNECTELE *pConnectEle;
  1452. PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
  1453. ULONG RemainingPdu;
  1454. PMDL pMdl;
  1455. PFILE_OBJECT pFileObject;
  1456. ULONG ReceiveLength;
  1457. BOOLEAN QuickRoute;
  1458. BOOLEAN FromCopyData;
  1459. pConnectEle = pLowerConn->pUpperConnection;
  1460. status = STATUS_SUCCESS;
  1461. // subtract session header and any bytes that the client took
  1462. //
  1463. BytesAvailable -= *BytesTaken;
  1464. //
  1465. // put together an Irp stack location to process the receive and pass down
  1466. // to the transport.
  1467. //
  1468. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1469. pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1470. //
  1471. // check if this will be a multiple rcv session pdu. If it is then
  1472. // allocate a partial MDL to be used for mapping part of the first
  1473. // MDL in each chunk received
  1474. //
  1475. RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
  1476. ReceiveLength = RemainingPdu;
  1477. PUSH_LOCATION(0x19);
  1478. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  1479. // this code should not be hit if called by CopyDataandIndicate
  1480. // which is in the indicate buffer state since it adjusts the bytesInXport
  1481. // which is also set by the code in TdiReceiveHndlr in the INDICATE_BUFFER
  1482. // state before calling CopyDataandIndicate. Also, CopyDataandIndicate
  1483. // does not want this routine to set the state to fillIrp when Bytes
  1484. // Available < RemainingPdu
  1485. //
  1486. FromCopyData = (pLowerConn->StateRcv == INDICATE_BUFFER);
  1487. if (!FromCopyData)
  1488. {
  1489. QuickRoute = TRUE;
  1490. // we need this code within the check since this routine is also called by the
  1491. // HandleNewSessionPdu routine, which calls IoCallDriver, which
  1492. // increments the stack location itself.
  1493. //
  1494. ASSERT(pIrp->CurrentLocation > 1);
  1495. if (BytesAvailable == RemainingPdu)
  1496. {
  1497. if (pClientParams->ReceiveLength >= BytesAvailable)
  1498. {
  1499. // *** FAST PATH CASE ****
  1500. goto ExitCode;
  1501. }
  1502. }
  1503. else
  1504. if (BytesAvailable < RemainingPdu ) // need more data from transport
  1505. {
  1506. PUSH_LOCATION(0x14);
  1507. // it is possible for the client to pass down an irp with no
  1508. // MDL in it, so we check for that here
  1509. //
  1510. if (pIrp->MdlAddress)
  1511. {
  1512. PUSH_LOCATION(0x14);
  1513. //
  1514. // save the client's irp address since the session pdu will arrive
  1515. // in several chunks, and we need to continually pass the irp to the
  1516. // transport for each chunk.
  1517. //
  1518. //pConnectEle->pIrpRcv = pIrp;
  1519. // NOTE: the pIrp is NOT saved here because the irp is about
  1520. // to be passed back to the transport. Hence we do not want
  1521. // to accidently complete it in DisconnectHandlrNotOs
  1522. // if a disconnect comes in while the irp is in the transport.
  1523. // pIrpRcv is set to pIrp in Completion Rcv while we have
  1524. // the irp in our possession.
  1525. //
  1526. // keep the initial Mdl(chain) since we need to
  1527. // to copy new data after the existing data, when the session pdu arrives
  1528. // as several chunks from TCP. Keeping the Mdl around allows us to
  1529. // reconstruct the original Mdl chain when we are all done.
  1530. //
  1531. pLowerConn->pMdl = pIrp->MdlAddress;
  1532. //
  1533. // this call maps the client's Mdl so that on each partial Mdl creation
  1534. // we don't go through a mapping and unmapping (when MmPrepareMdlForReuse)
  1535. // is called in the completion routine.
  1536. //
  1537. (PVOID)MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority);
  1538. pMdl = pIrp->MdlAddress;
  1539. // the nextmdl is setup to allow us to create a partial Mdl starting
  1540. // from the next one. CompletionRcv will adjust this if it needs to.
  1541. //
  1542. pConnectEle->pNextMdl = pMdl;
  1543. // need more data from the transport to fill this
  1544. // irp
  1545. //
  1546. CHECK_PTR(pConnectEle);
  1547. pConnectEle->pIrpRcv = NULL;
  1548. SET_STATERCV_LOWER(pLowerConn, FILL_IRP, FillIrp);
  1549. }
  1550. status = STATUS_MORE_PROCESSING_REQUIRED;
  1551. // if the client buffer is big enough, increment to the next
  1552. // io stack location and jump to the code that sets up the
  1553. // irp, since we always want to pass it to the transport in this
  1554. // case because the transport will hold onto the irp till it is full
  1555. // if it can. (faster)
  1556. //
  1557. if (pClientParams->ReceiveLength >= RemainingPdu)
  1558. {
  1559. // *** FAST PATH CASE ****
  1560. IoSetNextIrpStackLocation(pIrp);
  1561. pConnectEle->FreeBytesInMdl = ReceiveLength;
  1562. pConnectEle->CurrentRcvLen = RemainingPdu;
  1563. goto ExitCode2;
  1564. }
  1565. //
  1566. // if there is no mdl then we want to be able to go through the
  1567. // quick route below to return the null mdl right away, so
  1568. // don't set Quickroute false here.
  1569. //
  1570. }
  1571. else
  1572. if (BytesAvailable > RemainingPdu)
  1573. {
  1574. PUSH_LOCATION(0x15);
  1575. //
  1576. // there is too much data, so keep track of the
  1577. // fact that there is data left in the transport
  1578. // and get it when the irp completes through
  1579. // completion recv.
  1580. //
  1581. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  1582. // this calculation may have to be adjusted below if the client's
  1583. // buffer is too short. NOTE: BytesTaken have already been subtracted
  1584. // from BytesAvailable (above).
  1585. //
  1586. pConnectEle->BytesInXport = BytesAvailable - RemainingPdu;
  1587. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1588. KdPrint(("Nbt:Switching to Indicate Buff(Irp), Indic = %X, Pdusize=%X\n",
  1589. BytesIndicated,pConnectEle->TotalPcktLen));
  1590. status = STATUS_DATA_NOT_ACCEPTED;
  1591. }
  1592. // DEBUG*
  1593. //IoSetNextIrpStackLocation(pIrp);
  1594. }
  1595. else
  1596. {
  1597. QuickRoute = FALSE;
  1598. }
  1599. //
  1600. // if the receive buffer is too short then flag it so when the client
  1601. // passes another buffer to NBT, nbt will pass it to the transport
  1602. //
  1603. //if (BytesAvailable > pClientParams->ReceiveLength )
  1604. {
  1605. // so just check for too short of a client buffer.
  1606. //
  1607. if (RemainingPdu > pClientParams->ReceiveLength)
  1608. {
  1609. PUSH_LOCATION(0x17);
  1610. ReceiveLength = pClientParams->ReceiveLength;
  1611. //
  1612. // Adjust the number of bytes left in the transport up by the number of
  1613. // bytes not taken by the client. Be sure not to add in the number
  1614. // of bytes in the transport twice, since it could have been done
  1615. // above where the state is set to INDICATE_BUFFER
  1616. //
  1617. if (status == STATUS_DATA_NOT_ACCEPTED)
  1618. {
  1619. // BytesInXport was already incremented to account for any
  1620. // amount over remainingPdu, so just add the amount that the
  1621. // client buffer is short of RemainingPdu
  1622. //
  1623. PUSH_LOCATION(0x18);
  1624. if (BytesAvailable > ReceiveLength )
  1625. {
  1626. pConnectEle->BytesInXport += (RemainingPdu - ReceiveLength);
  1627. }
  1628. // the client has not taken all of the data , but has returned
  1629. // a buffer that is ReceiveLength long, therefore the amount
  1630. // that the client needs to take is just the total pdu - rcvlength.
  1631. //
  1632. pConnectEle->ReceiveIndicated = (RemainingPdu - ReceiveLength);
  1633. }
  1634. else
  1635. {
  1636. //
  1637. // BytesInXport has not been incremented yet so add the entire
  1638. // amount that the client buffer is too short by. Check if
  1639. // the client's buffer will take all of the data.
  1640. //
  1641. if (BytesAvailable > ReceiveLength )
  1642. {
  1643. pConnectEle->BytesInXport += (BytesAvailable - ReceiveLength);
  1644. }
  1645. // the client has not taken all of the data , but has returned
  1646. // a buffer that is ReceiveLength long, therefore the amount
  1647. // that the client needs to take is just what was indicated
  1648. // to the client - recvlength.
  1649. //
  1650. pConnectEle->ReceiveIndicated = (RemainingPdu - ReceiveLength);
  1651. }
  1652. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1653. KdPrint(("Nbt:Switching to PartialRcv for Irp. RecvInd. =%X, RemainPdu %X Avail %X\n",
  1654. pConnectEle->ReceiveIndicated,RemainingPdu,BytesAvailable));
  1655. }
  1656. }
  1657. ExitCode:
  1658. // keep track of data in MDL so we know when it is full and we need to
  1659. // return it to the user. CurrentRcvLen tells us how many bytes the current
  1660. // Irp can have max when the Mdl is full.
  1661. //
  1662. pConnectEle->FreeBytesInMdl = ReceiveLength;
  1663. pConnectEle->CurrentRcvLen = ReceiveLength;
  1664. if (ReceiveLength > RemainingPdu)
  1665. {
  1666. pConnectEle->CurrentRcvLen = RemainingPdu;
  1667. }
  1668. if (QuickRoute)
  1669. {
  1670. //
  1671. // check if we can copy the data to the client's MDL
  1672. // right here. If the indication is too short pass an Irp down
  1673. // to the transport.
  1674. //
  1675. BytesIndicated -= *BytesTaken;
  1676. if ((ReceiveLength <= BytesIndicated))
  1677. {
  1678. ULONG BytesCopied;
  1679. PUSH_LOCATION(0x76);
  1680. if (pIrp->MdlAddress)
  1681. {
  1682. status = TdiCopyBufferToMdl(
  1683. (PVOID)((PUCHAR)pBuffer + *BytesTaken),
  1684. 0,
  1685. ReceiveLength,
  1686. pIrp->MdlAddress,
  1687. 0,
  1688. &BytesCopied);
  1689. }
  1690. else
  1691. {
  1692. //
  1693. // No Mdl, so just return the irp to the client, and then
  1694. // return success to the caller so we tell the transport that
  1695. // we took only BytesTaken
  1696. //
  1697. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1698. KdPrint(("Nbt:No MDL, so complete Irp\n"));
  1699. PUSH_LOCATION(0x77);
  1700. BytesCopied = 0;
  1701. }
  1702. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1703. KdPrint(("Nbt:Copy to client Buffer RcvLen=%X,StateRcv=%X\n",
  1704. ReceiveLength,pLowerConn->StateRcv));
  1705. pIrp->IoStatus.Information = BytesCopied;
  1706. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1707. //
  1708. // now call the irp completion routine, shorting out the io
  1709. // subsystem - to process the irp
  1710. //
  1711. CTESpinFreeAtDpc(pLowerConn);
  1712. status = CompletionRcv(NULL,pIrp,(PVOID)pLowerConn);
  1713. //
  1714. // tell the transport we took all the data that we did take.
  1715. //
  1716. *BytesTaken += BytesCopied;
  1717. IF_DBG(NBT_DEBUG_FASTPATH)
  1718. KdPrint(("f"));
  1719. //
  1720. // complete the irp back to the client if required
  1721. //
  1722. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  1723. {
  1724. PUSH_LOCATION(0x76);
  1725. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1726. KdPrint(("Nbt:Completing Irp Quickly\n"));
  1727. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  1728. }
  1729. // since we have called CompletionRcv, that routine has
  1730. // adjusted the refcount and InRcvHandlr flag, so return this
  1731. // status to cause the caller to return directly
  1732. CTESpinLockAtDpc(pLowerConn);
  1733. return(STATUS_RECEIVE_EXPEDITED);
  1734. }
  1735. else
  1736. {
  1737. //
  1738. // make the next stack location the current one. Normally IoCallDriver
  1739. // would do this but we are not going through IoCallDriver here, since the
  1740. // Irp is just passed back with RcvIndication.
  1741. //
  1742. IoSetNextIrpStackLocation(pIrp);
  1743. }
  1744. }
  1745. ExitCode2:
  1746. pIrpSp->CompletionRoutine = CompletionRcv;
  1747. pIrpSp->Context = (PVOID)pLowerConn;
  1748. // set Control flags so the completion routine is always invoked.
  1749. pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
  1750. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1751. pIrpSp->MinorFunction = TDI_RECEIVE;
  1752. pFileObject = pLowerConn->pFileObject;
  1753. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  1754. pIrpSp->FileObject = pFileObject;
  1755. pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pFileObject);
  1756. pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1757. pParams->ReceiveFlags = pClientParams->ReceiveFlags;
  1758. // Set the correct receive length in the irp in case the client has
  1759. // passed one down that is larger than the message
  1760. //
  1761. pParams->ReceiveLength = ReceiveLength;
  1762. //
  1763. // just check for a zero length send, where the client has
  1764. // passed down an Irp with a null mdl, or the pdu size is zero. We don't want to pass
  1765. // that to the transport because it will hold onto it till the next
  1766. // pdu comes in from the wire - we want to complete the irp when this routine
  1767. // returns. When this is called from CopyDataAndIndicate don't
  1768. // to this because copydataandindicate does all the checks.
  1769. //
  1770. if (!FromCopyData)
  1771. {
  1772. if ((RemainingPdu == 0) || !pIrp->MdlAddress)
  1773. {
  1774. //
  1775. // the call to IoCompleteRequest will call completionRcv which will
  1776. // decrement the RefCount. Similarly returning status success will
  1777. // cause the caller to decrement the ref count, so increment one
  1778. // more time here to account for this second decrement.
  1779. //
  1780. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  1781. CTESpinFreeAtDpc(pLowerConn);
  1782. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  1783. CTESpinLockAtDpc(pLowerConn);
  1784. status = STATUS_SUCCESS;
  1785. }
  1786. else
  1787. status = STATUS_MORE_PROCESSING_REQUIRED;
  1788. }
  1789. return(status);
  1790. }
  1791. //----------------------------------------------------------------------------
  1792. NTSTATUS
  1793. ClientBufferOverFlow(
  1794. IN tLOWERCONNECTION *pLowerConn,
  1795. IN tCONNECTELE *pConnEle,
  1796. IN PIRP pIrp,
  1797. IN ULONG BytesRcvd
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. This routine completes the Irp by tracking the number of bytes received
  1802. Arguments:
  1803. DeviceObject - unused.
  1804. Irp - Supplies Irp that the transport has finished processing.
  1805. Context - Supplies the pLowerConn - the connection data structure
  1806. Return Value:
  1807. The final status from the operation (success or an exception).
  1808. --*/
  1809. {
  1810. // *TODO*
  1811. ASSERT(0);
  1812. switch (pLowerConn->StateRcv)
  1813. {
  1814. case PARTIAL_RCV:
  1815. case FILL_IRP:
  1816. case NORMAL:
  1817. case INDICATE_BUFFER:
  1818. default:
  1819. ;
  1820. }
  1821. return(STATUS_SUCCESS);
  1822. }
  1823. //----------------------------------------------------------------------------
  1824. NTSTATUS
  1825. CompletionRcv(
  1826. IN PDEVICE_OBJECT DeviceObject,
  1827. IN PIRP Irp,
  1828. IN PVOID Context
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. This routine completes the Irp by tracking the number of bytes received
  1833. Arguments:
  1834. DeviceObject - unused.
  1835. Irp - Supplies Irp that the transport has finished processing.
  1836. Context - Supplies the pLowerConn - the connection data structure
  1837. Return Value:
  1838. The final status from the operation (success or an exception).
  1839. --*/
  1840. {
  1841. register tCONNECTELE *pConnectEle;
  1842. NTSTATUS status;
  1843. ULONG BytesRcvd;
  1844. tLOWERCONNECTION *pLowerConn;
  1845. PKDPC pDpc;
  1846. CTELockHandle OldIrq;
  1847. CTELockHandle OldIrq2;
  1848. PMDL pMdl;
  1849. PIO_STACK_LOCATION pIrpSp;
  1850. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  1851. BOOLEAN AllowDereference=TRUE;
  1852. //
  1853. // Do some checking to keep the Io system happy - propagate the pending
  1854. // bit up the irp stack frame.... if it was set by the driver below then
  1855. // it must be set by me
  1856. //
  1857. if (Irp->PendingReturned)
  1858. {
  1859. IoMarkIrpPending(Irp);
  1860. }
  1861. // check the bytes recvd
  1862. pLowerConn = (tLOWERCONNECTION *)Context;
  1863. //
  1864. // if the link has disconnected, do not process the irp, just pass it
  1865. // up the chain.
  1866. //
  1867. CTESpinLock(pLowerConn,OldIrq);
  1868. if (!NT_SUCCESS(Irp->IoStatus.Status) || !pLowerConn->pUpperConnection)
  1869. {
  1870. PUSH_LOCATION(0x1);
  1871. if (pLowerConn->StateRcv == FILL_IRP)
  1872. {
  1873. PUSH_LOCATION(0x1);
  1874. Irp->MdlAddress = pLowerConn->pMdl;
  1875. ASSERT(Irp->MdlAddress);
  1876. }
  1877. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, RejectAnyData);
  1878. //
  1879. // the rcv failed so kill the connection since
  1880. // we can't keep track of message boundaries any more.
  1881. //
  1882. CTESpinFree(pLowerConn,OldIrq);
  1883. OutOfRsrcKill(pLowerConn);
  1884. CTESpinLock(pLowerConn,OldIrq);
  1885. status = STATUS_SUCCESS;
  1886. goto ExitCode;
  1887. }
  1888. pConnectEle = pLowerConn->pUpperConnection;
  1889. // keep track of how many bytes have been received
  1890. //
  1891. BytesRcvd = (ULONG)Irp->IoStatus.Information;
  1892. pConnectEle->BytesRcvd += BytesRcvd;
  1893. //
  1894. // subtract the number of bytes rcvd from the length of the client
  1895. // buffer
  1896. // so when more data arrives we can determine if we are going to
  1897. // overflow the client buffer.
  1898. //
  1899. pConnectEle->FreeBytesInMdl -= BytesRcvd;
  1900. pIrpSp = IoGetCurrentIrpStackLocation(Irp);
  1901. pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1902. pLowerConn->BytesRcvd += BytesRcvd;
  1903. CHECK_PTR(pConnectEle);
  1904. if (Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW)
  1905. {
  1906. //
  1907. // the client's buffer was too short - probably because he said it
  1908. // was longer than it really was
  1909. //
  1910. PUSH_LOCATION(0x1a);
  1911. KdPrint(("Nbt:Client Buffer Too short on CompletionRcv\n"));
  1912. if (pLowerConn->StateRcv == FILL_IRP)
  1913. {
  1914. PUSH_LOCATION(0x1a);
  1915. Irp->MdlAddress = pLowerConn->pMdl;
  1916. ASSERT(Irp->MdlAddress);
  1917. }
  1918. pConnectEle->BytesRcvd = 0; // reset for the next session pdu
  1919. status = ClientBufferOverFlow(pLowerConn,pConnectEle,Irp,BytesRcvd);
  1920. //
  1921. // the client's buffer was too short so kill the connection since
  1922. // we can't keep track of message boundaries any more.
  1923. //
  1924. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, RejectAnyData);
  1925. CTESpinFree(pLowerConn,OldIrq);
  1926. OutOfRsrcKill(pLowerConn);
  1927. CTESpinLock(pLowerConn,OldIrq);
  1928. goto ExitCode;
  1929. }
  1930. else if ((pConnectEle->FreeBytesInMdl == 0) ||
  1931. (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen))
  1932. {
  1933. INCR_COUNT(C1);
  1934. //
  1935. // this case handles when the Irp MDL is full or the whole pdu has been
  1936. // received.
  1937. //
  1938. //
  1939. // reset the MDL fields back to where they were
  1940. // if this was a multi-rcv session pdu
  1941. //
  1942. //
  1943. if (pLowerConn->StateRcv == FILL_IRP)
  1944. {
  1945. INCR_COUNT(C2);
  1946. PUSH_LOCATION(0x1b);
  1947. Irp->MdlAddress = pLowerConn->pMdl;
  1948. ASSERT(Irp->MdlAddress);
  1949. //
  1950. // allow the MDL to be used again for the next session PDU
  1951. //
  1952. pMdl = pConnectEle->pNewMdl;
  1953. MmPrepareMdlForReuse(pMdl);
  1954. pConnectEle->OffsetFromStart = 0;
  1955. }
  1956. CHECK_PTR(pConnectEle);
  1957. pConnectEle->pIrpRcv = NULL;
  1958. //
  1959. // we have received all of the data
  1960. // so complete back to the client
  1961. //
  1962. status = STATUS_SUCCESS;
  1963. //
  1964. // the amount of data in this irp is the CurrentRcvLen which
  1965. // could be less than BytesRcvd when the client passes down
  1966. // short rcv buffers.
  1967. //
  1968. Irp->IoStatus.Information = pConnectEle->CurrentRcvLen;
  1969. if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
  1970. {
  1971. pConnectEle->BytesRcvd = 0; // reset for the next session pdu
  1972. Irp->IoStatus.Status = STATUS_SUCCESS;
  1973. }
  1974. else
  1975. {
  1976. PUSH_LOCATION(0x27);
  1977. //
  1978. // this MDL must be too short to take the whole pdu, so set the
  1979. // status to buffer overflow.
  1980. //
  1981. Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  1982. }
  1983. //
  1984. // The client may have passed down a too short irp which we are
  1985. // tracking with ReceiveIndicated, so set state to partialrcv if
  1986. // necessary.
  1987. //
  1988. if (pConnectEle->ReceiveIndicated == 0)
  1989. {
  1990. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  1991. }
  1992. else
  1993. {
  1994. PUSH_LOCATION(0x26);
  1995. //
  1996. // there may still be data left in the transport
  1997. //
  1998. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1999. KdPrint(("Nbt:Short Rcv, still data indicated to client\n"));
  2000. SET_STATERCV_LOWER(pLowerConn, PARTIAL_RCV, PartialRcv);
  2001. }
  2002. //
  2003. // Check if there is still more data in the transport or if the client
  2004. // has been indicated with more data and has subsequently posted a rcv
  2005. // which we must get now and pass to the transport.
  2006. //
  2007. if ((pConnectEle->BytesInXport) || (pLowerConn->StateRcv == PARTIAL_RCV))
  2008. {
  2009. INCR_COUNT(C3);
  2010. //
  2011. // send down another
  2012. // irp to get the data and complete the client's current irp.
  2013. //
  2014. PUSH_LOCATION(0x1c);
  2015. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2016. KdPrint(("Nbt:ComplRcv BytesInXport= %X, %X\n",pConnectEle->BytesInXport,
  2017. pLowerConn));
  2018. if (pLowerConn->StateRcv != PARTIAL_RCV)
  2019. {
  2020. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  2021. pLowerConn->BytesInIndicate = 0;
  2022. }
  2023. CTESpinFree(pLowerConn,OldIrq);
  2024. IoAcquireCancelSpinLock(&OldIrq);
  2025. IoSetCancelRoutine(Irp,NULL);
  2026. IoReleaseCancelSpinLock(OldIrq);
  2027. // Complete the current Irp
  2028. IoCompleteRequest(Irp,IO_NETWORK_INCREMENT);
  2029. CTESpinLock(pLowerConn,OldIrq);
  2030. // rather than call HandleNewSessionPdu directly, we queue a
  2031. // Dpc since streams does not currently expect to get a recv
  2032. // posted while it is processing an indication response. The
  2033. // Dpc will run when streams is all done, and it should handle
  2034. // this posted receive ok.
  2035. if (pLowerConn->StateRcv == PARTIAL_RCV)
  2036. {
  2037. //
  2038. // check if the client has passed down another rcv buffer
  2039. // and if so, start a Dpc which will pass down the client's
  2040. // buffer.
  2041. //
  2042. if (!IsListEmpty(&pConnectEle->RcvHead))
  2043. {
  2044. if (pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('p')))
  2045. {
  2046. KeInitializeDpc(pDpc, DpcGetRestOfIndication, (PVOID)pLowerConn);
  2047. KeInsertQueueDpc(pDpc,NULL,NULL);
  2048. //
  2049. // we don't want to dereference pLowerConn at the end
  2050. // since we will use it in the DPC routine.
  2051. //
  2052. CTESpinFree(pLowerConn,OldIrq);
  2053. return(STATUS_MORE_PROCESSING_REQUIRED);
  2054. }
  2055. else
  2056. {
  2057. CTESpinFreeAtDpc(pLowerConn);
  2058. OutOfRsrcKill(pLowerConn);
  2059. CTESpinLockAtDpc(pLowerConn);
  2060. }
  2061. }
  2062. }
  2063. else if (pLowerConn->StateRcv != FILL_IRP)
  2064. {
  2065. if (pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('q')))
  2066. {
  2067. //
  2068. // just get the session hdr to start with so we know how large
  2069. // the pdu is, then get the rest of the pdu after that completes.
  2070. //
  2071. KeInitializeDpc(pDpc, DpcHandleNewSessionPdu, (PVOID)pLowerConn);
  2072. KeInsertQueueDpc(pDpc,NULL,(PVOID)sizeof(tSESSIONHDR));
  2073. //
  2074. // we don't want to dereference pLowerConn at the end
  2075. // since we will use it in the DPC routine.
  2076. //
  2077. CTESpinFree(pLowerConn,OldIrq);
  2078. return(STATUS_MORE_PROCESSING_REQUIRED);
  2079. }
  2080. else
  2081. {
  2082. CTESpinFreeAtDpc(pLowerConn);
  2083. OutOfRsrcKill(pLowerConn);
  2084. CTESpinLockAtDpc(pLowerConn);
  2085. }
  2086. }
  2087. else
  2088. {
  2089. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2090. KdPrint (("Nbt.CompletionRcv: * pLowerConn=<%p>, IP=<%x>\n",
  2091. pLowerConn, pLowerConn->SrcIpAddr));
  2092. }
  2093. status = STATUS_MORE_PROCESSING_REQUIRED;
  2094. goto ExitCode;
  2095. }
  2096. }
  2097. else if (pConnectEle->BytesRcvd < pConnectEle->TotalPcktLen)
  2098. {
  2099. ULONG Bytes;
  2100. INCR_COUNT(C4);
  2101. PUSH_LOCATION(0x1d);
  2102. //
  2103. // in this case we have not received all of the data from the transport
  2104. // for this session pdu, so tell the io subystem not to finish processing
  2105. // the irp yet if it is not a partial Rcv.
  2106. //
  2107. status = STATUS_MORE_PROCESSING_REQUIRED;
  2108. // clean up the partial mdl.
  2109. //
  2110. pMdl = pConnectEle->pNewMdl;
  2111. MmPrepareMdlForReuse(pMdl);
  2112. // set where the next rcvd data will start, by setting the pNextMdl and
  2113. // offset from start.
  2114. //
  2115. pMdl = pConnectEle->pNextMdl;
  2116. ASSERT(pMdl);
  2117. Bytes = BytesRcvd + pConnectEle->OffsetFromStart;
  2118. if (Bytes < MmGetMdlByteCount(pMdl))
  2119. {
  2120. PUSH_LOCATION(0x74);
  2121. //
  2122. // All of this data will fit into the current Mdl, and
  2123. // the next data will start in the same Mdl (if there is more data)
  2124. //
  2125. pConnectEle->OffsetFromStart += BytesRcvd;
  2126. IF_DBG(NBT_DEBUG_FILLIRP)
  2127. KdPrint(("~"));
  2128. }
  2129. else
  2130. {
  2131. //
  2132. // sum the Mdl lengths until we find enough space for the data
  2133. // to fit into.
  2134. //
  2135. IF_DBG(NBT_DEBUG_FILLIRP)
  2136. KdPrint(("^"));
  2137. PUSH_LOCATION(0x75);
  2138. SumMdlLengths(pMdl,Bytes,pConnectEle);
  2139. }
  2140. // since we are holding on to the rcv Irp, set up a cancel routine
  2141. IoAcquireCancelSpinLock(&OldIrq2);
  2142. // if the session was disconnected while the transport had the
  2143. // irp, then cancel the irp now...
  2144. //
  2145. if ((pConnectEle->state != NBT_SESSION_UP) || Irp->Cancel)
  2146. {
  2147. CHECK_PTR(pConnectEle);
  2148. pConnectEle->pIrpRcv = NULL;
  2149. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, RejectAnyData);
  2150. IoReleaseCancelSpinLock(OldIrq2);
  2151. CTESpinFree(pLowerConn,OldIrq);
  2152. // since the irp has been cancelled, don't touch it.
  2153. // return status success so the IO subsystem passes the irp
  2154. // back to the owner.
  2155. //
  2156. status = STATUS_SUCCESS;
  2157. // Irp->IoStatus.Status = STATUS_CANCELLED;
  2158. // IoCompleteRequest(Irp,IO_NETWORK_INCREMENT);
  2159. // the irp is being cancelled in mid session pdu. We can't
  2160. // recover since we have given the client only part of a pdu,
  2161. // therefore disconnect the connection.
  2162. OutOfRsrcKill(pLowerConn);
  2163. CTESpinLock(pLowerConn,OldIrq);
  2164. }
  2165. else
  2166. {
  2167. // setup the cancel routine
  2168. IoSetCancelRoutine(Irp, NbtCancelFillIrpRoutine);
  2169. // the pIrpRcv value is set to Zero when the irp is in the
  2170. // tranport, so we can't accidently complete it twice in
  2171. // disconnectHandlrNotOs when a disconnect occurs and the
  2172. // transport has the irp. So here we save the value again so FillIrp
  2173. // will work correctly.
  2174. //
  2175. pConnectEle->pIrpRcv = Irp;
  2176. // set the irp mdl back to its original so that a cancel will
  2177. // find the irp in the right state
  2178. //
  2179. Irp->MdlAddress = pLowerConn->pMdl;
  2180. IoReleaseCancelSpinLock(OldIrq2);
  2181. }
  2182. }
  2183. else
  2184. {
  2185. //IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2186. KdPrint(("Too Many Bytes Rcvd!! Rcvd# = %d, TotalLen = %d,NewBytes =%d,%X\n",
  2187. pConnectEle->BytesRcvd,pConnectEle->TotalPcktLen,
  2188. Irp->IoStatus.Information,pLowerConn));
  2189. ASSERT(0);
  2190. // this status will return the irp to the user
  2191. //
  2192. status = STATUS_SUCCESS;
  2193. if (pLowerConn->StateRcv == FILL_IRP)
  2194. {
  2195. PUSH_LOCATION(0x1f);
  2196. Irp->MdlAddress = pLowerConn->pMdl;
  2197. Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  2198. Irp->IoStatus.Information = 0;
  2199. //
  2200. // allow the MDL to be used again for the next session PDU
  2201. //
  2202. pMdl = pConnectEle->pNewMdl;
  2203. MmPrepareMdlForReuse(pMdl);
  2204. }
  2205. pConnectEle->OffsetFromStart = 0;
  2206. pConnectEle->BytesRcvd = 0;
  2207. SET_STATERCV_LOWER(pLowerConn, NORMAL, pLowerConn->CurrentStateProc);
  2208. //WHAT ELSE TO DO HERE OTHER THAN KILL THE CONNECTION, SINCE WE ARE
  2209. // PROBABLY OFF WITH RESPECT TO THE SESSION HDR....
  2210. // ....RESET THE CONNECTION ????
  2211. CTESpinFree(pLowerConn,OldIrq);
  2212. OutOfRsrcKill(pLowerConn);
  2213. CTESpinLock(pLowerConn,OldIrq);
  2214. }
  2215. ExitCode:
  2216. //
  2217. // quickly check if we can just decrement the ref count without calling
  2218. // NBT_DEREFERENCE_LOWERCONN - this function is __inline!!
  2219. //
  2220. PUSH_LOCATION(0x52);
  2221. DerefLowerConnFast (pLowerConn, OldIrq);
  2222. return(status);
  2223. UNREFERENCED_PARAMETER( DeviceObject );
  2224. }
  2225. //----------------------------------------------------------------------------
  2226. __inline
  2227. NTSTATUS
  2228. RcvHandlrNotOs (
  2229. IN PVOID ReceiveEventContext,
  2230. IN PVOID ConnectionContext,
  2231. IN USHORT ReceiveFlags,
  2232. IN ULONG BytesIndicated,
  2233. IN ULONG BytesAvailable,
  2234. OUT PULONG BytesTaken,
  2235. IN PVOID pTsdu,
  2236. OUT PVOID *RcvBuffer
  2237. )
  2238. /*++
  2239. Routine Description:
  2240. This routine is the receive event indication handler.
  2241. It is called when an session packet arrives from the network, when the
  2242. session has already been established (NBT_SESSION_UP state). The routine
  2243. looks for a receive buffer first and failing that looks for a receive
  2244. indication handler to pass the message to.
  2245. Arguments:
  2246. pClientEle - ptr to the connecition record for this session
  2247. Return Value:
  2248. NTSTATUS - Status of receive operation
  2249. --*/
  2250. {
  2251. NTSTATUS status;
  2252. PLIST_ENTRY pRcv;
  2253. PVOID pRcvElement;
  2254. tCLIENTELE *pClientEle;
  2255. tSESSIONHDR UNALIGNED *pSessionHdr;
  2256. tLOWERCONNECTION *pLowerConn;
  2257. tCONNECTELE *pConnectEle;
  2258. CTELockHandle OldIrq;
  2259. PIRP pIrp;
  2260. ULONG ClientBytesTaken;
  2261. BOOLEAN DebugMore;
  2262. ULONG RemainingPdu;
  2263. ULONG uSavedBytesIndicated = BytesIndicated;
  2264. //********************************************************************
  2265. //********************************************************************
  2266. //
  2267. // NOTE: A copy of this procedure is in Tdihndlr.c - it is inlined for
  2268. // the NT case. Therefore, only change this procedure and then
  2269. // copy the procedure body to Tdihndlr.c
  2270. //
  2271. //
  2272. //********************************************************************
  2273. //********************************************************************
  2274. // get the ptr to the lower connection, and from that get the ptr to the
  2275. // upper connection block
  2276. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  2277. pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
  2278. //
  2279. // Session ** UP ** processing
  2280. //
  2281. *BytesTaken = 0;
  2282. pConnectEle = pLowerConn->pUpperConnection;
  2283. ASSERT(pConnectEle->pClientEle);
  2284. ASSERT(BytesIndicated >= sizeof(tSESSIONHDR));
  2285. // this routine can get called by the next part of a large pdu, so that
  2286. // we don't always started at the begining of a pdu. The Bytes Rcvd
  2287. // value is set to zero in CompletionRcv when a new pdu is expected
  2288. //
  2289. if (pConnectEle->BytesRcvd == 0)
  2290. {
  2291. if (pSessionHdr->Type == NBT_SESSION_MESSAGE)
  2292. {
  2293. //
  2294. // expecting the start of a new session Pkt, so get the length out
  2295. // of the pTsdu passed in
  2296. //
  2297. pConnectEle->TotalPcktLen = myntohl(pSessionHdr->UlongLength);
  2298. // remove the Session header by adjusting the data pointer
  2299. pTsdu = (PVOID)((PUCHAR)pTsdu + sizeof(tSESSIONHDR));
  2300. // shorten the number of bytes since we have stripped off the
  2301. // session header
  2302. BytesIndicated -= sizeof(tSESSIONHDR);
  2303. BytesAvailable -= sizeof(tSESSIONHDR);
  2304. *BytesTaken = sizeof(tSESSIONHDR);
  2305. }
  2306. //
  2307. // Session Keep Alive
  2308. //
  2309. else
  2310. if (pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE)
  2311. {
  2312. // session keep alives are simply discarded, since the act of sending
  2313. // a keep alive indicates the session is still alive, otherwise the
  2314. // transport would report an error.
  2315. // tell the transport that we took the Pdu
  2316. *BytesTaken = sizeof(tSESSIONHDR);
  2317. return(STATUS_SUCCESS);
  2318. }
  2319. else
  2320. {
  2321. // IF_DBG(NBT_DEBUG_DISCONNECT)
  2322. KdPrint(("Nbt.RcvHandlrNotOs: Unexpected SessionPdu rcvd:type=%X\n",
  2323. pSessionHdr->Type));
  2324. // ASSERT(0);
  2325. *BytesTaken = BytesIndicated;
  2326. return(STATUS_SUCCESS);
  2327. }
  2328. }
  2329. //
  2330. // check if there are any receive buffers queued against this connection
  2331. //
  2332. if (!IsListEmpty(&pConnectEle->RcvHead))
  2333. {
  2334. // get the first buffer off the receive list
  2335. pRcv = RemoveHeadList(&pConnectEle->RcvHead);
  2336. #ifndef VXD
  2337. pRcvElement = CONTAINING_RECORD(pRcv,IRP,Tail.Overlay.ListEntry);
  2338. // the cancel routine was set when this irp was posted to Nbt, so
  2339. // clear it now, since the irp is being passed to the transport
  2340. //
  2341. IoAcquireCancelSpinLock(&OldIrq);
  2342. IoSetCancelRoutine((PIRP)pRcvElement,NULL);
  2343. IoReleaseCancelSpinLock(OldIrq);
  2344. #else
  2345. pRcvElement = CONTAINING_RECORD(pRcv, RCV_CONTEXT, ListEntry ) ;
  2346. #endif
  2347. //
  2348. // this buffer is actually an Irp, so pass it back to the transport
  2349. // as a return parameter
  2350. //
  2351. *RcvBuffer = pRcvElement;
  2352. return(STATUS_MORE_PROCESSING_REQUIRED);
  2353. }
  2354. //
  2355. // No receives on this connection. Is there a receive event handler for this
  2356. // address?
  2357. //
  2358. pClientEle = pConnectEle->pClientEle;
  2359. //
  2360. // For safe
  2361. //
  2362. if (NULL == pClientEle) {
  2363. return(STATUS_DATA_NOT_ACCEPTED);
  2364. }
  2365. #ifdef VXD
  2366. //
  2367. // there is always a receive event handler in the Nt case - it may
  2368. // be the default handler, but it is there, so no need for test.
  2369. //
  2370. if (pClientEle->evReceive)
  2371. #endif
  2372. {
  2373. // check that we have not received more data than we should for
  2374. // this session Pdu. i.e. part of the next session pdu. BytesRcvd may
  2375. // have a value other than zero if the pdu has arrived in two chunks
  2376. // and the client has taken the previous one in the indication rather
  2377. // than passing back an Irp.
  2378. //
  2379. #if DBG
  2380. DebugMore = FALSE;
  2381. #endif
  2382. RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
  2383. if (BytesAvailable >= RemainingPdu)
  2384. {
  2385. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2386. KdPrint(("Nbt.RcvHandlrNotOs: More Data Recvd than expecting! Avail= %X,TotalLen= %X,state=%x\n",
  2387. BytesAvailable,pConnectEle->TotalPcktLen,pLowerConn->StateRcv));
  2388. #if DBG
  2389. DebugMore =TRUE;
  2390. #endif
  2391. // shorten the indication to the client so that they don't
  2392. // get more data than the end of the pdu
  2393. //
  2394. BytesAvailable = RemainingPdu;
  2395. if (BytesIndicated > BytesAvailable)
  2396. {
  2397. BytesIndicated = BytesAvailable;
  2398. }
  2399. //
  2400. // We always indicated at raised IRQL since we call freelockatdispatch
  2401. // below
  2402. //
  2403. ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE | TDI_RECEIVE_AT_DISPATCH_LEVEL;
  2404. }
  2405. else
  2406. {
  2407. // the transport may have has this flag on. We need to
  2408. // turn it off if the entire message is not present, where entire
  2409. // message means within the bytesAvailable length. We deliberately
  2410. // use bytesavailable so that Rdr/Srv can know that the next
  2411. // indication will be a new message if they set bytestaken to
  2412. // bytesavailable.
  2413. //
  2414. ReceiveFlags &= ~TDI_RECEIVE_ENTIRE_MESSAGE;
  2415. ReceiveFlags |= TDI_RECEIVE_AT_DISPATCH_LEVEL;
  2416. #ifndef VXD
  2417. BytesAvailable = RemainingPdu;
  2418. #endif
  2419. }
  2420. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2421. KdPrint(("Nbt.RcvHandlrNotOs: Calling Client's EventHandler <%x> BytesIndicated=<%x>, BytesAvailable=<%x>\n",
  2422. pClientEle->evReceive, BytesIndicated, BytesAvailable));
  2423. //
  2424. // NT-specific code locks pLowerConn before calling this routine,
  2425. //
  2426. CTESpinFreeAtDpc(pLowerConn);
  2427. // call the Client Event Handler
  2428. ClientBytesTaken = 0;
  2429. status = (*pClientEle->evReceive)(
  2430. pClientEle->RcvEvContext,
  2431. pConnectEle->ConnectContext,
  2432. ReceiveFlags,
  2433. BytesIndicated,
  2434. BytesAvailable,
  2435. &ClientBytesTaken,
  2436. pTsdu,
  2437. &pIrp);
  2438. CTESpinLockAtDpc(pLowerConn);
  2439. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2440. KdPrint(("Nbt.RcvHandlrNotOs: Client's EventHandler returned <%x>, BytesTaken=<%x>, pIrp=<%x>\n",
  2441. status, ClientBytesTaken, pIrp));
  2442. #if DBG
  2443. if (DebugMore)
  2444. {
  2445. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2446. KdPrint(( "Nbt.RcvHandlrNotOs: Client TOOK %X bytes, pIrp = %X,status =%X\n",
  2447. ClientBytesTaken,pIrp,status));
  2448. }
  2449. #endif
  2450. if (!pLowerConn->pUpperConnection)
  2451. {
  2452. // the connection was disconnected in the interim
  2453. // so do nothing.
  2454. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2455. {
  2456. CTEIoComplete(pIrp,STATUS_CANCELLED,0);
  2457. *BytesTaken = BytesAvailable;
  2458. return(STATUS_SUCCESS);
  2459. }
  2460. }
  2461. else
  2462. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2463. {
  2464. ASSERT(pIrp);
  2465. //
  2466. // the client may pass back a receive in the pIrp.
  2467. // In this case pIrp is a valid receive request Irp
  2468. // and the status is MORE_PROCESSING
  2469. //
  2470. // don't put these lines outside the if incase the client
  2471. // does not set ClientBytesTaken when it returns an error
  2472. // code... we don't want to use the value then
  2473. //
  2474. // count the bytes received so far. Most of the bytes
  2475. // will be received in the CompletionRcv handler in TdiHndlr.c
  2476. pConnectEle->BytesRcvd += ClientBytesTaken;
  2477. // The client has taken some of the data at least...
  2478. *BytesTaken += ClientBytesTaken;
  2479. ASSERT(*BytesTaken <= uSavedBytesIndicated);
  2480. *RcvBuffer = pIrp;
  2481. // ** FAST PATH **
  2482. return(status);
  2483. }
  2484. else
  2485. //
  2486. // no irp was returned... the client just took some of the bytes..
  2487. //
  2488. if (status == STATUS_SUCCESS)
  2489. {
  2490. // count the bytes received so far.
  2491. pConnectEle->BytesRcvd += ClientBytesTaken;
  2492. *BytesTaken += ClientBytesTaken;
  2493. //
  2494. // In STATUS_SUCCESS case, the client take part of the data or simply set
  2495. // ClientBytesTake to BytesAvailable to tell us that it want to skip to
  2496. // the next message
  2497. //
  2498. ASSERT(ClientBytesTaken <= BytesIndicated || ClientBytesTaken == BytesAvailable);
  2499. //
  2500. // look at how much data was taken and adjust some counts
  2501. //
  2502. if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
  2503. {
  2504. // ** FAST PATH **
  2505. CHECK_PTR(pConnectEle);
  2506. pConnectEle->BytesRcvd = 0; // reset for the next session pdu
  2507. return(status);
  2508. }
  2509. else
  2510. if (pConnectEle->BytesRcvd > pConnectEle->TotalPcktLen)
  2511. {
  2512. //IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2513. KdPrint(("Too Many Bytes Rcvd!! Rcvd# = %d, TotalLen = %d\n",
  2514. pConnectEle->BytesRcvd,pConnectEle->TotalPcktLen));
  2515. ASSERTMSG("Nbt:Client Took Too Much Data!!!\n",0);
  2516. //
  2517. // try to recover by saying that the client took all of the
  2518. // data so at least the transport is not confused too
  2519. //
  2520. *BytesTaken = uSavedBytesIndicated;
  2521. }
  2522. else
  2523. // the client did not take all of the data so
  2524. // keep track of the fact
  2525. {
  2526. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2527. KdPrint(("NBT:Client took Indication BytesRcvd=%X, TotalLen=%X BytesAvail %X ClientTaken %X\n",
  2528. pConnectEle->BytesRcvd,
  2529. pConnectEle->TotalPcktLen,
  2530. BytesAvailable,
  2531. ClientBytesTaken));
  2532. //
  2533. // the next time the client sends down a receive buffer
  2534. // the code will pass it to the transport and decrement the
  2535. // ReceiveIndicated counter which is set in Tdihndlr.c
  2536. }
  2537. }
  2538. else
  2539. if (status == STATUS_DATA_NOT_ACCEPTED)
  2540. {
  2541. // client has not taken ANY data...
  2542. //
  2543. // In this case the *BytesTaken is set to 4, the session hdr.
  2544. // since we really have taken that data to setup the PduSize
  2545. // in the pConnEle structure.
  2546. //
  2547. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2548. KdPrint(("Nbt.RcvHandlrNotOs: Status DATA NOT ACCEPTED returned from client Avail %X %X\n",
  2549. BytesAvailable,pConnectEle));
  2550. // the code in tdihndlr.c normally looks after incrementing
  2551. // the ReceiveIndicated count for data that is not taken by
  2552. // the client, but if it is a zero length send that code cannot
  2553. // detect it, so we put code here to handle that case
  2554. //
  2555. // It is possible for the client to do a disconnect after
  2556. // we release the spin lock on pLowerConn to call the Client's
  2557. // disconnect indication. If that occurs, do not overwrite
  2558. // the StateProc with PartialRcv
  2559. //
  2560. if ((pConnectEle->TotalPcktLen == 0) &&
  2561. (pConnectEle->state == NBT_SESSION_UP))
  2562. {
  2563. SET_STATERCV_LOWER(pLowerConn, PARTIAL_RCV, PartialRcv);
  2564. CHECK_PTR(pConnectEle);
  2565. pConnectEle->ReceiveIndicated = 0; // zero bytes waiting for client
  2566. }
  2567. else
  2568. {
  2569. //
  2570. // if any bytes were taken (i.e. the session hdr) then
  2571. // return status success. (otherwise the status is
  2572. // statusNotAccpeted).
  2573. //
  2574. if (*BytesTaken)
  2575. {
  2576. ASSERT(*BytesTaken <= uSavedBytesIndicated);
  2577. status = STATUS_SUCCESS;
  2578. }
  2579. }
  2580. //
  2581. // the next time the client sends down a receive buffer
  2582. // the code will pass it to the transport and decrement this
  2583. // counter.
  2584. }
  2585. else
  2586. ASSERT(0);
  2587. return(status);
  2588. }
  2589. #ifdef VXD
  2590. //
  2591. // there is always a receive event handler in the Nt case - it may
  2592. // be the default handler, but it is there, so no need for test.
  2593. //
  2594. else
  2595. {
  2596. //
  2597. // there is no client buffer to pass the data to, so keep
  2598. // track of the fact so when the next client buffer comes down
  2599. // we can get the data from the transport.
  2600. //
  2601. KdPrint(("NBT:Client did not have a Buffer posted, rcvs indicated =%X,BytesRcvd=%X, TotalLen=%X\n",
  2602. pConnectEle->ReceiveIndicated,
  2603. pConnectEle->BytesRcvd,
  2604. pConnectEle->TotalPcktLen));
  2605. // the routine calling this one increments ReceiveIndicated and sets the
  2606. // state to PartialRcv to keep track of the fact that there is data
  2607. // waiting in the transport
  2608. //
  2609. return(STATUS_DATA_NOT_ACCEPTED);
  2610. }
  2611. #endif
  2612. }
  2613. //----------------------------------------------------------------------------
  2614. __inline
  2615. VOID
  2616. DerefLowerConnFast(
  2617. IN tLOWERCONNECTION *pLowerConn,
  2618. IN CTELockHandle OldIrq
  2619. )
  2620. /*++
  2621. Routine Description:
  2622. This routine dereferences the lower connection and if someone has
  2623. tried to do that during the execution of the routine that called
  2624. this one, the pConnEle is dereferenced too.
  2625. Arguments:
  2626. Return Value:
  2627. --*/
  2628. {
  2629. if (pLowerConn->RefCount > 1)
  2630. {
  2631. // This is the FAST PATH
  2632. IF_DBG(NBT_DEBUG_REF)
  2633. KdPrint(("\t--pLowerConn=<%x:%d->%d>, <%d:%s>\n",
  2634. pLowerConn,pLowerConn->RefCount,(pLowerConn->RefCount-1),__LINE__,__FILE__));
  2635. pLowerConn->RefCount--;
  2636. ASSERT (pLowerConn->References[REF_LOWC_RCV_HANDLER]--);
  2637. CTESpinFree(pLowerConn,OldIrq);
  2638. }
  2639. else
  2640. {
  2641. CTESpinFree(pLowerConn,OldIrq);
  2642. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, FALSE);
  2643. }
  2644. }
  2645. //----------------------------------------------------------------------------
  2646. VOID
  2647. DpcGetRestOfIndication(
  2648. IN PKDPC pDpc,
  2649. IN PVOID Context,
  2650. IN PVOID SystemArgument1,
  2651. IN PVOID SystemArgument2
  2652. )
  2653. /*++
  2654. Routine Description:
  2655. This routine is called when the client has been indicated with more
  2656. data than they will take and there is a rcv buffer on their RcvHead
  2657. list when completion rcv runs.
  2658. Arguments:
  2659. Return Value:
  2660. --*/
  2661. {
  2662. NTSTATUS status;
  2663. CTELockHandle OldIrq;
  2664. tCONNECTELE *pConnEle;
  2665. PIRP pIrp;
  2666. PIO_STACK_LOCATION pIrpSp;
  2667. tLOWERCONNECTION *pLowerConn=(tLOWERCONNECTION *)Context;
  2668. PLIST_ENTRY pEntry;
  2669. CTEMemFree((PVOID)pDpc);
  2670. CTESpinLockAtDpc(&NbtConfig.JointLock);
  2671. // a disconnect indication can come in any time and separate the lower and
  2672. // upper connections, so check for that
  2673. if (!pLowerConn->pUpperConnection || pLowerConn->StateRcv != PARTIAL_RCV)
  2674. {
  2675. PUSH_LOCATION(0xA4);
  2676. //
  2677. // Dereference pLowerConn
  2678. //
  2679. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, TRUE);
  2680. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2681. return;
  2682. }
  2683. CTESpinLockAtDpc(pLowerConn);
  2684. pConnEle = (tCONNECTELE *)pLowerConn->pUpperConnection;
  2685. if (!IsListEmpty(&pConnEle->RcvHead))
  2686. {
  2687. PUSH_LOCATION(0xA5);
  2688. pEntry = RemoveHeadList(&pConnEle->RcvHead);
  2689. CTESpinFreeAtDpc(pLowerConn);
  2690. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2691. pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
  2692. IoAcquireCancelSpinLock(&OldIrq);
  2693. IoSetCancelRoutine(pIrp,NULL);
  2694. IoReleaseCancelSpinLock(OldIrq);
  2695. //
  2696. // call the same routine that the client would call to post
  2697. // a recv buffer, except now we are in the PARTIAL_RCV state
  2698. // and the buffer will be passed to the transport.
  2699. //
  2700. status = NTReceive (pLowerConn->pDeviceContext, pIrp);
  2701. }
  2702. else
  2703. {
  2704. CTESpinFreeAtDpc(pLowerConn);
  2705. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2706. PUSH_LOCATION(0xA6);
  2707. }
  2708. //
  2709. // Dereference pLowerConn
  2710. //
  2711. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, FALSE);
  2712. }
  2713. //----------------------------------------------------------------------------
  2714. VOID
  2715. DpcHandleNewSessionPdu (
  2716. IN PKDPC pDpc,
  2717. IN PVOID Context,
  2718. IN PVOID SystemArgument1,
  2719. IN PVOID SystemArgument2
  2720. )
  2721. /*++
  2722. Routine Description:
  2723. This routine simply calls HandleNewSessionPdu from a Dpc started in
  2724. NewSessionCompletionRoutine.
  2725. Arguments:
  2726. Return Value:
  2727. --*/
  2728. {
  2729. CTEMemFree((PVOID)pDpc);
  2730. HandleNewSessionPdu((tLOWERCONNECTION *)Context,
  2731. PtrToUlong(SystemArgument1),
  2732. PtrToUlong(SystemArgument2));
  2733. }
  2734. //----------------------------------------------------------------------------
  2735. VOID
  2736. HandleNewSessionPdu (
  2737. IN tLOWERCONNECTION *pLowerConn,
  2738. IN ULONG Offset,
  2739. IN ULONG ToGet
  2740. )
  2741. /*++
  2742. Routine Description:
  2743. This routine handles the case when a session pdu starts in the middle of
  2744. a data indication from the transport. It gets an Irp from the free list
  2745. and formulates a receive to pass to the transport to get that data. The
  2746. assumption is that the client has taken all data preceding the next session
  2747. pdu. If the client hasn't then this routine should not be called yet.
  2748. Arguments:
  2749. Return Value:
  2750. pConnectionContext - connection context returned to the transport(connection to use)
  2751. NTSTATUS - Status of receive operation
  2752. --*/
  2753. {
  2754. NTSTATUS status;
  2755. ULONG BytesTaken;
  2756. PIRP pIrp;
  2757. PFILE_OBJECT pFileObject;
  2758. PMDL pMdl;
  2759. ULONG BytesToGet;
  2760. tCONNECTELE *pConnEle;
  2761. pIrp = NULL;
  2762. BytesTaken = 0;
  2763. // we grab the joint lock because it is needed to separate the lower and
  2764. // upper connections, so with it we can check if they have been separated.
  2765. //
  2766. CTESpinLockAtDpc(&NbtConfig.JointLock);
  2767. pConnEle = pLowerConn->pUpperConnection;
  2768. // a disconnect indication can come in any time and separate the lower and
  2769. // upper connections, so check for that
  2770. if (!pLowerConn->pUpperConnection)
  2771. {
  2772. //
  2773. // remove the reference from CompletionRcv
  2774. //
  2775. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, TRUE);
  2776. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2777. return;
  2778. }
  2779. //
  2780. // get an Irp from the list
  2781. //
  2782. status = GetIrp(&pIrp);
  2783. if (!NT_SUCCESS(status))
  2784. {
  2785. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2786. KdPrint(("Nbt:Unable to get an Irp - Closing Connection!!\n",0));
  2787. status = OutOfRsrcKill(pLowerConn);
  2788. //
  2789. // remove the reference from CompletionRcv
  2790. //
  2791. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, FALSE);
  2792. return;
  2793. }
  2794. CTESpinLockAtDpc(pLowerConn);
  2795. //
  2796. // be sure the connection has not disconnected in the meantime...
  2797. //
  2798. if (pLowerConn->State != NBT_SESSION_UP)
  2799. {
  2800. NbtFreeIrp(pIrp);
  2801. CTESpinFreeAtDpc(pLowerConn);
  2802. //
  2803. // remove the reference from CompletionRcv
  2804. //
  2805. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, TRUE);
  2806. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2807. return;
  2808. }
  2809. pFileObject = pLowerConn->pFileObject;
  2810. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  2811. // use the indication buffer for the receive.
  2812. pMdl = pLowerConn->pIndicateMdl;
  2813. // this flag is set below so we know if there is data in the indicate buffer
  2814. // or not.
  2815. if (Offset)
  2816. {
  2817. PVOID NewAddress;
  2818. PMDL pNewMdl;
  2819. // there is still data in the indication buffer ,so only
  2820. // fill the empty space. This means adjusting the Mdl to
  2821. // to only map the last portion of the Indication Buffer
  2822. NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pMdl)
  2823. + Offset);
  2824. // create a partial MDL so that the new data is copied after the existing data
  2825. // in the MDL.
  2826. //
  2827. // 0 for length means map the rest of the buffer
  2828. //
  2829. pNewMdl = pConnEle->pNewMdl;
  2830. IoBuildPartialMdl(pMdl,pNewMdl,NewAddress,0);
  2831. pMdl = pNewMdl;
  2832. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2833. KdPrint(("Nbt:Mapping IndicBuffer to partial Mdl Offset=%X, ToGet=%X %X\n",
  2834. Offset,ToGet,
  2835. pLowerConn));
  2836. }
  2837. else
  2838. {
  2839. CHECK_PTR(pLowerConn);
  2840. pLowerConn->BytesInIndicate = 0;
  2841. }
  2842. //
  2843. // Only get the amount of data specified, which is either the 4 byte header
  2844. // or the rest of the pdu so that we never have
  2845. // more than one session pdu in the indicate buffer.
  2846. //
  2847. BytesToGet = ToGet;
  2848. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  2849. TdiBuildReceive(
  2850. pIrp,
  2851. IoGetRelatedDeviceObject(pFileObject),
  2852. pFileObject,
  2853. NewSessionCompletionRoutine,
  2854. (PVOID)pLowerConn,
  2855. pMdl,
  2856. (ULONG)TDI_RECEIVE_NORMAL,
  2857. BytesToGet); // only ask for the number of bytes left and no more
  2858. CTESpinFreeAtDpc(pLowerConn);
  2859. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2860. CHECK_COMPLETION(pIrp);
  2861. status = IoCallDriver(IoGetRelatedDeviceObject(pFileObject),pIrp);
  2862. }
  2863. //----------------------------------------------------------------------------
  2864. NTSTATUS
  2865. NewSessionCompletionRoutine (
  2866. IN PDEVICE_OBJECT DeviceObject,
  2867. IN PIRP pIrp,
  2868. IN PVOID pContext
  2869. )
  2870. /*++
  2871. Routine Description:
  2872. This routine handles the completion of the receive to get the remaining
  2873. data left in the transport when a session PDU starts in the middle of
  2874. an indication from the transport. This routine is run as the completion
  2875. of a recv Irp passed to the transport by NBT, to get the remainder of the
  2876. data in the transport.
  2877. The routine then calls the normal receive handler, which can either
  2878. consume the data or pass back an Irp. If an Irp is passed back then
  2879. the data is copied into that irp in this routine.
  2880. Arguments:
  2881. Return Value:
  2882. pConnectionContext - connection context returned to the transport(connection to use)
  2883. NTSTATUS - Status of receive operation
  2884. --*/
  2885. {
  2886. NTSTATUS status, IrpStatus;
  2887. ULONG BytesTaken;
  2888. tCONNECTELE *pConnEle;
  2889. PVOID pData;
  2890. KIRQL OldIrq;
  2891. PMDL pMdl;
  2892. ULONG BytesIndicated;
  2893. ULONG BytesAvailable;
  2894. PKDPC pDpc;
  2895. tLOWERCONNECTION *pLowerConn;
  2896. ULONG Length;
  2897. ULONG PduLen;
  2898. PIRP pRetIrp;
  2899. // we grab the joint lock because it is needed to separate the lower and
  2900. // upper connections, so with it we can check if they have been separated.
  2901. //
  2902. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2903. pLowerConn = (tLOWERCONNECTION *)pContext;
  2904. pConnEle = pLowerConn->pUpperConnection;
  2905. CTESpinLockAtDpc(pLowerConn);
  2906. // a disconnect indication can come in any time and separate the lower and
  2907. // upper connections, so check for that
  2908. //
  2909. if (!pConnEle)
  2910. {
  2911. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2912. status = STATUS_UNSUCCESSFUL;
  2913. goto ExitRoutine;
  2914. }
  2915. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2916. BytesTaken = 0;
  2917. pMdl = pLowerConn->pIndicateMdl;
  2918. pData = MmGetMdlVirtualAddress(pMdl);
  2919. //
  2920. // The Indication buffer may have more data in it than what we think
  2921. // was left in the transport, because the transport may have received more
  2922. // data in the intervening time. Check for this case.
  2923. //
  2924. if (pIrp->IoStatus.Information > pConnEle->BytesInXport)
  2925. {
  2926. // no data left in transport
  2927. //
  2928. CHECK_PTR(pConnEle);
  2929. pConnEle->BytesInXport = 0;
  2930. }
  2931. else
  2932. {
  2933. //
  2934. // subtract what we just retrieved from the transport, from the count
  2935. // of data left in the transport
  2936. //
  2937. pConnEle->BytesInXport -= (ULONG)pIrp->IoStatus.Information;
  2938. }
  2939. //
  2940. // there may be data still in the indication buffer,
  2941. // so add that amount to what we just received.
  2942. //
  2943. pLowerConn->BytesInIndicate += (USHORT)pIrp->IoStatus.Information;
  2944. BytesIndicated = pLowerConn->BytesInIndicate;
  2945. // put the irp back on its free list
  2946. CHECK_PTR(pIrp);
  2947. pIrp->MdlAddress = NULL;
  2948. IrpStatus = pIrp->IoStatus.Status;
  2949. NbtFreeIrp(pIrp);
  2950. //
  2951. // we need to set the bytes available to be the data in the Xport + the
  2952. // bytes in the indicate buffer, so that
  2953. // ReceiveIndicated gets set to the correct value if the client does
  2954. // not take all of data
  2955. //
  2956. BytesAvailable = pConnEle->BytesInXport + BytesIndicated;
  2957. pRetIrp = NULL;
  2958. // if the number of bytes is 4 then we just have the header and must go
  2959. // back to the transport for the rest of the pdu, or we have a keep
  2960. // alive pdu...
  2961. //
  2962. //
  2963. // This could be a session keep alive pdu so check the pdu type. Keep
  2964. // alives just go to the RcvHndlrNotOs routine and return, doing nothing.
  2965. // They have a length of zero, so the overall length is 4 and they could
  2966. // be confused for session pdus otherwise.
  2967. //
  2968. status = STATUS_SUCCESS;
  2969. if (BytesIndicated == sizeof(tSESSIONHDR))
  2970. {
  2971. PUSH_LOCATION(0x1e)
  2972. if (((tSESSIONHDR UNALIGNED *)pData)->Type == NBT_SESSION_MESSAGE)
  2973. {
  2974. // if there is still data in the transport we must send down an
  2975. // irp to get the data, however, if there is no data left in
  2976. // the transport, then the data will come up on its own, into
  2977. // the indicate_buffer case in the main Receivehandler.
  2978. //
  2979. if (pConnEle->BytesInXport)
  2980. {
  2981. PUSH_LOCATION(0x1e);
  2982. // tell the DPC routine to get the data at an offset of 4 for length Length
  2983. //
  2984. // this is the first indication to find out how large the pdu is, so
  2985. // get the length and go get the rest of the pdu.
  2986. //
  2987. Length = myntohl(((tSESSIONHDR UNALIGNED *)pData)->UlongLength);
  2988. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2989. KdPrint(("Nbt:Got Pdu Hdr in sessioncmplionroutine, PduLen =%X\n",Length));
  2990. // it is possible to get a zero length pdu, in which case we
  2991. // do NOT need to go to the transport to get more data
  2992. //
  2993. if (Length)
  2994. {
  2995. PUSH_LOCATION(0x1e);
  2996. //
  2997. // now go get this amount of data and add it to the header
  2998. //
  2999. CTESpinFree(pLowerConn,OldIrq);
  3000. if (pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('r')))
  3001. {
  3002. // check that the pdu is not going to overflow the indicate buffer.
  3003. //
  3004. if (Length > NBT_INDICATE_BUFFER_SIZE - sizeof(tSESSIONHDR))
  3005. {
  3006. Length = NBT_INDICATE_BUFFER_SIZE - sizeof(tSESSIONHDR);
  3007. }
  3008. ASSERTMSG("Nbt:Getting ZERO bytes from Xport!!\n",Length);
  3009. KeInitializeDpc(pDpc, DpcHandleNewSessionPdu, (PVOID)pLowerConn);
  3010. KeInsertQueueDpc(pDpc, ULongToPtr(sizeof(tSESSIONHDR)), ULongToPtr(Length));
  3011. // clean up the partial mdl since we are going to turn around and reuse
  3012. // it in HandleNewSessionPdu above..
  3013. //
  3014. // THIS CALL SHOULD NOT BE NEEDED SINCE THE INDICATE BUFFER IS NON_PAGED
  3015. // POOL
  3016. // MmPrepareMdlForReuse(pConnEle->pNewMdl);
  3017. // return this status to stop to tell the io subsystem to stop processing
  3018. // this irp when we return it.
  3019. //
  3020. return(STATUS_MORE_PROCESSING_REQUIRED);
  3021. }
  3022. OutOfRsrcKill(pLowerConn);
  3023. CTESpinLock (pLowerConn,OldIrq);
  3024. status = STATUS_INSUFFICIENT_RESOURCES;
  3025. goto ExitRoutine;
  3026. }
  3027. }
  3028. }
  3029. }
  3030. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3031. KdPrint(("Nbt:NewSessComplRcv BytesinXport= %X,InIndicate=%X Indic. %X,Avail=%X %X\n",
  3032. pConnEle->BytesInXport,pLowerConn->BytesInIndicate,BytesIndicated,
  3033. BytesAvailable,pConnEle->pLowerConnId));
  3034. if (!NT_SUCCESS(IrpStatus))
  3035. {
  3036. ASSERTMSG("Nbt:Not Expecting a Bad Status Code\n",0);
  3037. goto ExitRoutine;
  3038. }
  3039. //
  3040. // check if we have a whole pdu in the indicate buffer or not. IF not
  3041. // then just return and wait for more data to hit the TdiReceiveHandler
  3042. // code. This check passes KeepAlives correctly since they have a pdu
  3043. // length of 0, and adding the header gives 4, their overall length.
  3044. //
  3045. PduLen = myntohl(((tSESSIONHDR UNALIGNED *)pData)->UlongLength);
  3046. if ((BytesIndicated < PduLen + sizeof(tSESSIONHDR)) &&
  3047. (BytesIndicated != NBT_INDICATE_BUFFER_SIZE))
  3048. {
  3049. PUSH_LOCATION(0x1f);
  3050. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3051. KdPrint(("Nbt:Returning in NewSessionCompletion BytesIndicated = %X\n", BytesIndicated));
  3052. }
  3053. else
  3054. {
  3055. PUSH_LOCATION(0x20);
  3056. status = CopyDataandIndicate (NULL,
  3057. (PVOID)pLowerConn,
  3058. 0, // rcv flags
  3059. BytesIndicated,
  3060. BytesAvailable,
  3061. &BytesTaken,
  3062. pData,
  3063. (PVOID)&pRetIrp);
  3064. }
  3065. ExitRoutine:
  3066. //
  3067. // check if an irp is passed back, so we don't Deref in that case.
  3068. //
  3069. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  3070. {
  3071. //
  3072. // quickly check if we can just decrement the ref count without calling
  3073. // NBT_DEREFERENCE_LOWERCONN
  3074. //
  3075. PUSH_LOCATION(0x51);
  3076. DerefLowerConnFast(pLowerConn,OldIrq);
  3077. }
  3078. else
  3079. {
  3080. CTESpinFree(pLowerConn,OldIrq);
  3081. }
  3082. return(STATUS_MORE_PROCESSING_REQUIRED);
  3083. }
  3084. //----------------------------------------------------------------------------
  3085. NTSTATUS
  3086. NtBuildIndicateForReceive (
  3087. IN tLOWERCONNECTION *pLowerConn,
  3088. IN ULONG Length,
  3089. OUT PVOID *ppIrp
  3090. )
  3091. /*++
  3092. Routine Description:
  3093. This routine sets up the indicate buffer to get data from the transport
  3094. when the indicate buffer already has some data in it. A partial MDL is
  3095. built and the attached to the irp.
  3096. before we indicate.
  3097. Arguments:
  3098. Return Value:
  3099. NTSTATUS - Status of receive operation
  3100. --*/
  3101. {
  3102. NTSTATUS status;
  3103. PIRP pIrp;
  3104. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  3105. PIO_STACK_LOCATION pIrpSp;
  3106. tCONNECTELE *pConnEle;
  3107. PMDL pNewMdl;
  3108. PVOID NewAddress;
  3109. //
  3110. // get an Irp from the list
  3111. //
  3112. status = GetIrp(&pIrp);
  3113. if (!NT_SUCCESS(status))
  3114. {
  3115. KdPrint(("NBT:Unable to get Irp, Kill connection\n"));
  3116. CTESpinFreeAtDpc(pLowerConn);
  3117. OutOfRsrcKill(pLowerConn);
  3118. CTESpinLockAtDpc(pLowerConn);
  3119. return(STATUS_INSUFFICIENT_RESOURCES);
  3120. }
  3121. pConnEle= pLowerConn->pUpperConnection;
  3122. NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl)
  3123. + pLowerConn->BytesInIndicate);
  3124. // create a partial MDL so that the new data is copied after the existing data
  3125. // in the MDL.
  3126. //
  3127. // 0 for length means map the rest of the buffer
  3128. //
  3129. pNewMdl = pConnEle->pNewMdl;
  3130. IoBuildPartialMdl(pLowerConn->pIndicateMdl,pNewMdl,NewAddress,0);
  3131. ASSERT (pLowerConn->pFileObject->Type == IO_TYPE_FILE);
  3132. TdiBuildReceive(
  3133. pIrp,
  3134. IoGetRelatedDeviceObject(pLowerConn->pFileObject),
  3135. pLowerConn->pFileObject,
  3136. NewSessionCompletionRoutine,
  3137. (PVOID)pLowerConn,
  3138. pNewMdl,
  3139. (ULONG)TDI_RECEIVE_NORMAL,
  3140. Length);
  3141. //
  3142. // we need to set the next Irp stack location because this irp is returned
  3143. // as a return parameter rather than being passed through IoCallDriver
  3144. // which increments the stack location itself
  3145. //
  3146. ASSERT(pIrp->CurrentLocation > 1);
  3147. IoSetNextIrpStackLocation(pIrp);
  3148. *ppIrp = (PVOID)pIrp;
  3149. return(STATUS_SUCCESS);
  3150. }
  3151. //----------------------------------------------------------------------------
  3152. NTSTATUS
  3153. NtBuildIrpForReceive (
  3154. IN tLOWERCONNECTION *pLowerConn,
  3155. IN ULONG Length,
  3156. OUT PVOID *ppIrp
  3157. )
  3158. /*++
  3159. Routine Description:
  3160. This routine gets an Irp to be used to receive data and hooks the indication
  3161. Mdl to it, so we can accumulate at least 128 bytes of data for the client
  3162. before we indicate.
  3163. Arguments:
  3164. Return Value:
  3165. NTSTATUS - Status of receive operation
  3166. --*/
  3167. {
  3168. NTSTATUS status;
  3169. PIRP pIrp;
  3170. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  3171. PIO_STACK_LOCATION pIrpSp;
  3172. //
  3173. // get an Irp from the list
  3174. //
  3175. status = GetIrp(&pIrp);
  3176. if (!NT_SUCCESS(status))
  3177. {
  3178. KdPrint(("NBT:Unable to get Irp, Kill connection\n"));
  3179. return(STATUS_INSUFFICIENT_RESOURCES);
  3180. }
  3181. CHECK_PTR(pLowerConn);
  3182. pLowerConn->BytesInIndicate = 0;
  3183. ASSERT (pLowerConn->pFileObject->Type == IO_TYPE_FILE);
  3184. TdiBuildReceive(
  3185. pIrp,
  3186. IoGetRelatedDeviceObject(pLowerConn->pFileObject),
  3187. pLowerConn->pFileObject,
  3188. NewSessionCompletionRoutine,
  3189. (PVOID)pLowerConn,
  3190. pLowerConn->pIndicateMdl,
  3191. (ULONG)TDI_RECEIVE_NORMAL,
  3192. Length);
  3193. //
  3194. // we need to set the next Irp stack location because this irp is returned
  3195. // as a return parameter rather than being passed through IoCallDriver
  3196. // which increments the stack location itself
  3197. //
  3198. ASSERT(pIrp->CurrentLocation > 1);
  3199. IoSetNextIrpStackLocation(pIrp);
  3200. *ppIrp = (PVOID)pIrp;
  3201. return(STATUS_SUCCESS);
  3202. }
  3203. #pragma inline_depth(0)
  3204. //----------------------------------------------------------------------------
  3205. NTSTATUS
  3206. CopyDataandIndicate(
  3207. IN PVOID ReceiveEventContext,
  3208. IN PVOID ConnectionContext,
  3209. IN USHORT ReceiveFlags,
  3210. IN ULONG BytesIndicated,
  3211. IN ULONG BytesAvailable,
  3212. OUT PULONG BytesTaken,
  3213. IN PVOID pTsdu,
  3214. OUT PIRP *ppIrp
  3215. )
  3216. /*++
  3217. Routine Description:
  3218. This routine combines data indicated with the indicate buffer to
  3219. indicate the total to the client. Any bytes Indicated are those bytes
  3220. in the indicate buffer. Bytes available adds in any bytes in the transport.
  3221. The idea here is to copy as much as possible from the indicate buffer and
  3222. then pass back an irp if there is still more data in the transport. If
  3223. no data left in the transport, this routine completes the client irp and
  3224. returns STATUS_SUCCESS.
  3225. Arguments:
  3226. Return Value:
  3227. NTSTATUS - Status of receive operation
  3228. --*/
  3229. {
  3230. NTSTATUS status;
  3231. tLOWERCONNECTION *pLowerConn;
  3232. tCONNECTELE *pConnEle;
  3233. ULONG BytesCopied;
  3234. ULONG Indicated;
  3235. ULONG Available;
  3236. ULONG Taken;
  3237. ULONG AmountAlreadyInIndicateBuffer;
  3238. PVOID pBuffer;
  3239. PIRP pIrp;
  3240. BOOLEAN bReIndicate=FALSE;
  3241. ULONG RemainingPdu;
  3242. ULONG ToCopy;
  3243. PKDPC pDpc;
  3244. ULONG SaveInXport;
  3245. ULONG PduSize;
  3246. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  3247. pConnEle = pLowerConn->pUpperConnection;
  3248. AmountAlreadyInIndicateBuffer = pLowerConn->BytesInIndicate;
  3249. //
  3250. // set the parameters for the call to the TdiReceiveHandler routine
  3251. //
  3252. Indicated = BytesIndicated;
  3253. Available = BytesAvailable;
  3254. Taken = 0;
  3255. // ASSERT(pLowerConn->StateRcv == INDICATE_BUFFER);
  3256. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3257. KdPrint(("Nbt:Amount In Indicate = %X\n",AmountAlreadyInIndicateBuffer));
  3258. // now that we have 128 bytes (plus the session hdr = 132 total) we
  3259. // can indicate to the client
  3260. pBuffer = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
  3261. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3262. KdPrint(("Nbt:FromCopyData, BytesAvail= %X,BytesInd= %X,BytesRcvd= %X,Amount=%X, %X,state=%X,RcvEC=%X\n",
  3263. Available,Indicated,pConnEle->BytesRcvd,
  3264. AmountAlreadyInIndicateBuffer,pLowerConn,pLowerConn->StateRcv,
  3265. ReceiveEventContext));
  3266. pIrp = NULL;
  3267. //
  3268. // Reset this count so that the routine processes the Session header correctly
  3269. //
  3270. CHECK_PTR(pConnEle);
  3271. pConnEle->BytesRcvd = 0;
  3272. PUSH_LOCATION(0x21);
  3273. status = RcvHandlrNotOs(
  3274. NULL,
  3275. ConnectionContext,
  3276. ReceiveFlags,
  3277. Indicated,
  3278. Available,
  3279. &Taken,
  3280. pBuffer,
  3281. (PVOID)&pIrp
  3282. );
  3283. //
  3284. // if the connection has disonnected, then just return
  3285. //
  3286. if (!pLowerConn->pUpperConnection)
  3287. {
  3288. *BytesTaken = BytesAvailable;
  3289. return(STATUS_SUCCESS);
  3290. }
  3291. // do not use pConnEle->TotalPcktLen here becauase it won't be set for
  3292. // keep alives - must use actual buffer to get length.
  3293. PduSize = myntohl(((tSESSIONHDR UNALIGNED *)pBuffer)->UlongLength) + sizeof(tSESSIONHDR);
  3294. RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  3295. if (Taken <= pLowerConn->BytesInIndicate)
  3296. {
  3297. pLowerConn->BytesInIndicate -= (USHORT)Taken;
  3298. }
  3299. else
  3300. {
  3301. pLowerConn->BytesInIndicate = 0;
  3302. }
  3303. if (pIrp)
  3304. {
  3305. PIO_STACK_LOCATION pIrpSp;
  3306. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  3307. ULONG ClientRcvLen;
  3308. PUSH_LOCATION(0x22);
  3309. //
  3310. // BytesInXport will be recalculated by ProcessIrp based on BytesAvailable
  3311. // and the ClientRcvLength, so set it to 0 here.
  3312. //
  3313. SaveInXport = pConnEle->BytesInXport;
  3314. CHECK_PTR(pConnEle);
  3315. pConnEle->BytesInXport = 0;
  3316. status = ProcessIrp(pLowerConn,
  3317. pIrp,
  3318. pBuffer,
  3319. &Taken,
  3320. Indicated,
  3321. Available);
  3322. //
  3323. // copy the data in the indicate buffer that was not taken by the client
  3324. // into the MDL and then update the bytes taken and pass the irp on downwar
  3325. // to the transport
  3326. //
  3327. ToCopy = Indicated - Taken;
  3328. // the Next stack location has the correct info in it because we
  3329. // called TdiRecieveHandler with a null ReceiveEventContext,
  3330. // so that routine does not increment the stack location
  3331. //
  3332. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  3333. pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  3334. ClientRcvLen = pParams->ReceiveLength;
  3335. // did the client's Pdu fit entirely into the indication buffer?
  3336. //
  3337. if (ClientRcvLen <= ToCopy)
  3338. {
  3339. PUSH_LOCATION(0x23);
  3340. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3341. KdPrint(("Nbt:Took some(or all) RemainingPdu= %X, ClientRcvLen= %X,InXport=%X %X\n",
  3342. RemainingPdu,ClientRcvLen,pConnEle->BytesInXport,pLowerConn));
  3343. // if ProcessIrp has recalculated the bytes in the Xport
  3344. // then set it back to where it should be, Since ProcessIrp will
  3345. // put all not taken bytes as bytes in the transport - but some
  3346. // of the bytes are still in the indicate buffer.
  3347. //
  3348. pConnEle->BytesInXport = SaveInXport;
  3349. // it could be a zero length send where the client returns a null
  3350. // mdl, or the client returns an mdl and the RcvLen is really zero.
  3351. //
  3352. if (pIrp->MdlAddress && ClientRcvLen)
  3353. {
  3354. TdiCopyBufferToMdl(pBuffer, // indicate buffer
  3355. Taken, // src offset
  3356. ClientRcvLen,
  3357. pIrp->MdlAddress,
  3358. 0, // dest offset
  3359. &BytesCopied);
  3360. }
  3361. else
  3362. BytesCopied = 0;
  3363. //
  3364. // check for data still in the transport - subtract data copied to
  3365. // Irp, since Taken was already subtracted.
  3366. //
  3367. pLowerConn->BytesInIndicate -= (USHORT)BytesCopied;
  3368. *BytesTaken = Taken + BytesCopied;
  3369. ASSERT(BytesCopied == ClientRcvLen);
  3370. // the client has received all of the data, so complete his irp
  3371. //
  3372. pIrp->IoStatus.Information = BytesCopied;
  3373. pIrp->IoStatus.Status = STATUS_SUCCESS;
  3374. // since we are completing it and TdiRcvHandler did not set the next
  3375. // one.
  3376. //
  3377. ASSERT(pIrp->CurrentLocation > 1);
  3378. // since we are completing the irp here, no need to call
  3379. // this, because it will complete through completionrcv.
  3380. IoSetNextIrpStackLocation(pIrp);
  3381. // there should not be any data in the indicate buffer since it
  3382. // only holds either 132 bytes or a whole pdu unless the client
  3383. // receive length is too short...
  3384. //
  3385. if (pLowerConn->BytesInIndicate)
  3386. {
  3387. PUSH_LOCATION(0x23);
  3388. // when the irp goes through completionRcv it should set the
  3389. // state to PartialRcv and the next posted buffer from
  3390. // the client should pickup this data.
  3391. CopyToStartofIndicate(pLowerConn,(Taken+BytesCopied));
  3392. }
  3393. else
  3394. {
  3395. //
  3396. // this will complete through CompletionRcv and for that
  3397. // reason it will get any more data left in the transport. The
  3398. // Completion routine will set the correct state for the rcv when
  3399. // it processes this Irp ( to INDICATED, if needed). ProcessIrp
  3400. // may have set ReceiveIndicated, so that CompletionRcv will
  3401. // set the state to PARTIAL_RCV when it runs.
  3402. //
  3403. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  3404. }
  3405. CTESpinFreeAtDpc(pLowerConn);
  3406. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  3407. CTESpinLockAtDpc(pLowerConn);
  3408. //
  3409. // this was undone by CompletionRcv, so redo them, since the
  3410. // caller will undo them again.
  3411. //
  3412. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  3413. return(STATUS_SUCCESS);
  3414. }
  3415. else
  3416. {
  3417. PUSH_LOCATION(0x24);
  3418. //
  3419. // there is still data that we need to get to fill the PDU. There
  3420. // may be more data left in the transport or not after the irp is
  3421. // filled.
  3422. // In either case the Irps' Mdl must be adjusted to account for
  3423. // filling part of it.
  3424. //
  3425. TdiCopyBufferToMdl(pBuffer, // IndicateBuffer
  3426. Taken, // src offset
  3427. ToCopy,
  3428. pIrp->MdlAddress,
  3429. 0, // dest offset
  3430. &BytesCopied);
  3431. //
  3432. // save the Mdl so we can reconstruct things later
  3433. //
  3434. pLowerConn->pMdl = pIrp->MdlAddress;
  3435. pConnEle->pNextMdl = pIrp->MdlAddress;
  3436. ASSERT(pIrp->MdlAddress);
  3437. //
  3438. // The irp is being passed back to the transport, so we NULL
  3439. // our ptr to it so we don't try to cancel it on a disconnect
  3440. //
  3441. CHECK_PTR(pConnEle);
  3442. pConnEle->pIrpRcv = NULL;
  3443. // Adjust the number of bytes in the Mdl chain so far since the
  3444. // completion routine will only count the bytes filled in by the
  3445. // transport
  3446. //
  3447. pConnEle->BytesRcvd += BytesCopied;
  3448. *BytesTaken = BytesIndicated;
  3449. //
  3450. // clear the number of bytes in the indicate buffer since the client
  3451. // has taken more than the data left in the Indicate buffer
  3452. //
  3453. CHECK_PTR(pLowerConn);
  3454. pLowerConn->BytesInIndicate = 0;
  3455. // decrement the client rcv len by the amount already put into the
  3456. // client Mdl
  3457. //
  3458. ClientRcvLen -= BytesCopied;
  3459. //
  3460. // if ProcessIrp did recalculate the bytes in the transport
  3461. // then set back to what it was. Process irp will do this
  3462. // recalculation if the clientrcv buffer is too short only.
  3463. //
  3464. pConnEle->BytesInXport = SaveInXport;
  3465. //
  3466. // adjust the number of bytes downward due to the client rcv
  3467. // buffer
  3468. //
  3469. if (ClientRcvLen < SaveInXport)
  3470. {
  3471. PUSH_LOCATION(0x24);
  3472. pConnEle->BytesInXport -= ClientRcvLen;
  3473. }
  3474. else
  3475. {
  3476. pConnEle->BytesInXport = 0;
  3477. }
  3478. // ProcessIrp will set bytesinXport and ReceiveIndicated - since
  3479. // the indicate buffer is empty that calculation of BytesInXport
  3480. // will be correct.
  3481. //
  3482. // We MUST set the state to FILL_IRP so that completion Rcv
  3483. // undoes the partial MDL stuff - i.e. it puts the original
  3484. // MdlAddress in the Irp, rather than the partial Mdl address.
  3485. // CompletionRcv will set the state to partial Rcv if ReceiveIndicated
  3486. // is not zero.
  3487. //
  3488. SET_STATERCV_LOWER(pLowerConn, FILL_IRP, FillIrp);
  3489. // the client is going to take more data from the transport with
  3490. // this Irp. Set the new Rcv Length that accounts for the data just
  3491. // copied to the Irp.
  3492. //
  3493. pParams->ReceiveLength = ClientRcvLen;
  3494. // keep track of data in MDL so we know when it is full and we need to
  3495. // return it to the user - ProcessIrp set it to ClientRcvLen, so
  3496. // shorten it here.
  3497. //
  3498. pConnEle->FreeBytesInMdl -= BytesCopied;
  3499. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3500. KdPrint(("Nbt:ClientRcvLen = %X, LeftinXport= %X RemainingPdu= %X %X\n",ClientRcvLen,
  3501. pConnEle->BytesInXport,RemainingPdu,pLowerConn));
  3502. // Build a partial Mdl to represent the client's Mdl chain since
  3503. // we have copied data to it, and the transport must copy
  3504. // more data to it after that data.
  3505. //
  3506. MakePartialMdl(pConnEle,pIrp,BytesCopied);
  3507. *ppIrp = pIrp;
  3508. // increments the stack location, since TdiReceiveHandler did not.
  3509. //
  3510. if (ReceiveEventContext)
  3511. {
  3512. ASSERT(pIrp->CurrentLocation > 1);
  3513. IoSetNextIrpStackLocation(pIrp);
  3514. return(STATUS_MORE_PROCESSING_REQUIRED);
  3515. }
  3516. else
  3517. {
  3518. // pass the Irp to the transport since we were called from
  3519. // NewSessionCompletionRoutine
  3520. //
  3521. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3522. KdPrint(("Nbt:Calling IoCallDriver\n"));
  3523. ASSERT(pIrp->CurrentLocation > 1);
  3524. CTESpinFreeAtDpc(pLowerConn);
  3525. CHECK_COMPLETION(pIrp);
  3526. ASSERT (pLowerConn->pFileObject->Type == IO_TYPE_FILE);
  3527. IoCallDriver(IoGetRelatedDeviceObject(pLowerConn->pFileObject),pIrp);
  3528. CTESpinLockAtDpc(pLowerConn);
  3529. return(STATUS_MORE_PROCESSING_REQUIRED);
  3530. }
  3531. }
  3532. }
  3533. else
  3534. {
  3535. PUSH_LOCATION(0x54);
  3536. //
  3537. // no Irp passed back, the client just took some or all of the data
  3538. //
  3539. *BytesTaken = Taken;
  3540. pLowerConn->BytesRcvd += Taken - sizeof(tSESSIONHDR);
  3541. ASSERT(*BytesTaken < 0x7FFFFFFF );
  3542. //
  3543. // if more than the indicate buffer is taken, then the client
  3544. // is probably trying to say it doesn't want any more of the
  3545. // message.
  3546. //
  3547. if (Taken > BytesIndicated)
  3548. {
  3549. //
  3550. // in this case the client has taken more than the indicated.
  3551. // We set bytesavailable to the message length in RcvHndlrNotOs,
  3552. // so the client has probably said BytesTaken=BytesAvailable.
  3553. // So kill the connection
  3554. // because we have no way of handling this case here, since
  3555. // part of the message may still be in the transport, and we
  3556. // might have to send the indicate buffer down there multiple
  3557. // times to get all of it...a mess! The Rdr only sets bytestaken =
  3558. // bytesAvailable under select error conditions anyway.
  3559. //
  3560. CTESpinFreeAtDpc(pLowerConn);
  3561. OutOfRsrcKill(pLowerConn);
  3562. CTESpinLockAtDpc(pLowerConn);
  3563. *BytesTaken = BytesAvailable;
  3564. }
  3565. else if (pLowerConn->StateRcv == PARTIAL_RCV)
  3566. {
  3567. // this may be a zero length send -that the client has
  3568. // decided not to accept. If so then the state will be set
  3569. // to PartialRcv. In this case do NOT go down to the transport
  3570. // and get the rest of the data, but wait for the client
  3571. // to post a rcv buffer.
  3572. //
  3573. PUSH_LOCATION(0x54);
  3574. return(STATUS_SUCCESS);
  3575. }
  3576. else if (Taken == PduSize)
  3577. {
  3578. //
  3579. // Must have taken all of the pdu data, so check for
  3580. // more data available - if so send down the indicate
  3581. // buffer to get it.
  3582. //
  3583. if (pConnEle->BytesInXport)
  3584. {
  3585. PUSH_LOCATION(0x28);
  3586. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3587. KdPrint(("Nbt:CopyData BytesInXport= %X, %X\n",pConnEle->BytesInXport,
  3588. pLowerConn));
  3589. //
  3590. // there is still data in the transport so Q a Dpc to use
  3591. // the indicate buffer to get the data
  3592. //
  3593. pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('s'));
  3594. if (pDpc)
  3595. {
  3596. KeInitializeDpc(pDpc, DpcHandleNewSessionPdu, (PVOID)pLowerConn);
  3597. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  3598. // get just the header first to see how large the pdu is
  3599. //
  3600. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  3601. KeInsertQueueDpc(pDpc,NULL,(PVOID)sizeof(tSESSIONHDR));
  3602. }
  3603. else
  3604. {
  3605. CTESpinFreeAtDpc(pLowerConn);
  3606. OutOfRsrcKill(pLowerConn);
  3607. CTESpinLockAtDpc(pLowerConn);
  3608. }
  3609. }
  3610. else
  3611. {
  3612. PUSH_LOCATION(0x29);
  3613. //
  3614. // clear the flag saying that we are using the indicate buffer
  3615. //
  3616. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  3617. }
  3618. PUSH_LOCATION(0x2a);
  3619. return(STATUS_SUCCESS);
  3620. }
  3621. else
  3622. {
  3623. //
  3624. // the client may have taken all the data in the
  3625. // indication!!, in which case return status success
  3626. // Note: that we check bytes available here not bytes
  3627. // indicated - since the client could take all indicated
  3628. // data but still leave data in the transport. If the client
  3629. // got told there was more available but only took the indicated,
  3630. // the we need to do the else and track ReceiveIndicated, but if
  3631. // Indicated == Available, then we take the if and wait for
  3632. // another indication from the transport.
  3633. //
  3634. if (Taken == BytesAvailable)
  3635. {
  3636. PUSH_LOCATION(0x4);
  3637. status = STATUS_SUCCESS;
  3638. }
  3639. else
  3640. {
  3641. // did not take all of the data in the Indication
  3642. //
  3643. PUSH_LOCATION(0x2b);
  3644. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3645. KdPrint(("Nbt:Took Part of indication... BytesRemaining= %X, LeftInXport= %X, %X\n",
  3646. pLowerConn->BytesInIndicate,pConnEle->BytesInXport,pLowerConn));
  3647. //
  3648. // The amount of data Indicated to the client should not exceed
  3649. // the Pdu size, so check that, since this routine could get
  3650. // called with bytesAvailable > than the Pdu size.
  3651. //
  3652. // That is checked above where we check if Taken > BytesIndicated.
  3653. SaveInXport = pConnEle->BytesInXport;
  3654. ASSERT(Taken <= PduSize);
  3655. status = ClientTookSomeOfTheData(pLowerConn,
  3656. Indicated,
  3657. Available,
  3658. Taken,
  3659. PduSize);
  3660. //
  3661. // Since the data may be divided between some in the transport
  3662. // and some in the indicate buffer do not let ClientTookSomeOf...
  3663. // recalculate the amount in the transport, since it assumes all
  3664. // untaken data is in the transport. Since the client did not
  3665. // take of the indication, the Bytes in Xport have not changed.
  3666. //
  3667. pConnEle->BytesInXport = SaveInXport;
  3668. //
  3669. // need to move the data forward in the indicate buffer so that
  3670. // it begins at the start of the buffer
  3671. //
  3672. if (Taken)
  3673. {
  3674. CopyToStartofIndicate(pLowerConn,Taken);
  3675. }
  3676. }
  3677. }
  3678. }
  3679. return(STATUS_SUCCESS);
  3680. }
  3681. //----------------------------------------------------------------------------
  3682. NTSTATUS
  3683. TdiConnectHandler (
  3684. IN PVOID pConnectEventContext,
  3685. IN int RemoteAddressLength,
  3686. IN PVOID pRemoteAddress,
  3687. IN int UserDataLength,
  3688. IN PVOID pUserData,
  3689. IN int OptionsLength,
  3690. IN PVOID pOptions,
  3691. OUT CONNECTION_CONTEXT *pConnectionContext,
  3692. OUT PIRP *ppAcceptIrp
  3693. )
  3694. /*++
  3695. Routine Description:
  3696. This routine is connect event handler. It is invoked when a request for
  3697. a connection has been received by the provider. NBT accepts the connection
  3698. on one of its connections in its LowerConnFree list
  3699. Initially a TCP connection is setup with this port. Then a Session Request
  3700. packet is sent across the connection to indicate the name of the destination
  3701. process. This packet is received in the RcvHandler.
  3702. For message-only mode, make session establishment automatic without the exchange of
  3703. messages. In this case, the best way to do this is to force the code through its paces.
  3704. The code path for "inbound" setup includes AcceptCompletionRoutine, Inbound, and
  3705. CompleteSessionSetup. We do this by creating a fake session request and feeding it into
  3706. the state machine.
  3707. As part of connection/session establishment, Netbt must notify
  3708. the consumer. Normally this is done after connection establishment when the session request
  3709. comes in. We must move this process up so that the consumer gets his notification and
  3710. yah/nay opportunity during connection acceptance, so we gets a chance to reject the connection.
  3711. Arguments:
  3712. pConnectEventContext - the context passed to the transport when this event was setup
  3713. RemoteAddressLength - the length of the source address (4 bytes for IP)
  3714. pRemoteAddress - a ptr to the source address
  3715. UserDataLength - the number of bytes of user data - includes the session Request hdr
  3716. pUserData - ptr the the user data passed in
  3717. OptionsLength - number of options to pass in
  3718. pOptions - ptr to the options
  3719. Return Value:
  3720. pConnectionContext - connection context returned to the transport(connection to use)
  3721. NTSTATUS - Status of receive operation
  3722. --*/
  3723. {
  3724. NTSTATUS status;
  3725. PFILE_OBJECT pFileObject;
  3726. PIRP pRequestIrp;
  3727. CONNECTION_CONTEXT pConnectionId;
  3728. tDEVICECONTEXT *pDeviceContext;
  3729. *pConnectionContext = NULL;
  3730. // convert the context value into the device context record ptr
  3731. pDeviceContext = (tDEVICECONTEXT *)pConnectEventContext;
  3732. IF_DBG(NBT_DEBUG_TDIHNDLR)
  3733. KdPrint(("pDeviceContxt = %X ConnectEv = %X",pDeviceContext,pConnectEventContext));
  3734. ASSERTMSG("Bad Device context passed to the Connection Event Handler",
  3735. pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
  3736. // get an Irp from the list
  3737. status = GetIrp(&pRequestIrp);
  3738. if (!NT_SUCCESS(status))
  3739. {
  3740. return(STATUS_DATA_NOT_ACCEPTED);
  3741. }
  3742. // call the non-OS specific routine to find a free connection.
  3743. status = ConnectHndlrNotOs(
  3744. pConnectEventContext,
  3745. RemoteAddressLength,
  3746. pRemoteAddress,
  3747. UserDataLength,
  3748. pUserData,
  3749. &pConnectionId);
  3750. if (!NT_SUCCESS(status))
  3751. {
  3752. IF_DBG(NBT_DEBUG_TDIHNDLR)
  3753. KdPrint(("NO FREE CONNECTIONS in connect handler\n"));
  3754. NbtFreeIrp(pRequestIrp);
  3755. NbtTrace(NBT_TRACE_INBOUND, ("ConnectHndlrNotOs return %!status!", status));
  3756. return(STATUS_DATA_NOT_ACCEPTED);
  3757. }
  3758. #ifdef _NETBIOSLESS
  3759. //
  3760. // MessageOnly mode. Establish session automatically.
  3761. //
  3762. // ******************************************************************************************
  3763. if (IsDeviceNetbiosless(pDeviceContext))
  3764. {
  3765. status = PerformInboundProcessing (pDeviceContext,
  3766. (tLOWERCONNECTION *) pConnectionId,
  3767. pRemoteAddress);
  3768. if (!NT_SUCCESS(status))
  3769. {
  3770. // IF_DBG(NBT_DEBUG_TDIHNDLR)
  3771. KdPrint(("MessageOnly connect processing rejected with status 0x%x\n", status));
  3772. NbtFreeIrp(pRequestIrp);
  3773. NbtTrace(NBT_TRACE_INBOUND, ("PerformInboundProecessing return %!status!", status));
  3774. return(STATUS_DATA_NOT_ACCEPTED);
  3775. }
  3776. }
  3777. // ******************************************************************************************
  3778. //
  3779. //
  3780. #endif
  3781. pFileObject = ((tLOWERCONNECTION *)pConnectionId)->pFileObject;
  3782. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  3783. TdiBuildAccept(
  3784. pRequestIrp,
  3785. IoGetRelatedDeviceObject(pFileObject),
  3786. pFileObject,
  3787. AcceptCompletionRoutine,
  3788. (PVOID)pConnectionId,
  3789. NULL,
  3790. NULL);
  3791. // we need to null the MDL address because the transport KEEPS trying to
  3792. // release buffers!! which do not exist!!!
  3793. //
  3794. CHECK_PTR(pRequestIrp);
  3795. pRequestIrp->MdlAddress = NULL;
  3796. // return the connection id to accept the connect indication on.
  3797. *pConnectionContext = (CONNECTION_CONTEXT)pConnectionId;
  3798. *ppAcceptIrp = pRequestIrp;
  3799. //
  3800. // make the next stack location the current one. Normally IoCallDriver
  3801. // would do this but we are not going through IoCallDriver here, since the
  3802. // Irp is just passed back with Connect Indication.
  3803. //
  3804. ASSERT(pRequestIrp->CurrentLocation > 1);
  3805. IoSetNextIrpStackLocation(pRequestIrp);
  3806. return(STATUS_MORE_PROCESSING_REQUIRED);
  3807. }
  3808. #ifdef _NETBIOSLESS
  3809. //----------------------------------------------------------------------------
  3810. static void
  3811. Inet_ntoa_nb(
  3812. ULONG Address,
  3813. PCHAR Buffer
  3814. )
  3815. /*++
  3816. Routine Description:
  3817. This routine converts an IP address into its "dotted quad" representation. The IP address is
  3818. expected to be in network byte order. No attempt is made to handle the other dotted notions as
  3819. defined in in.h. No error checking is done: all address values are permissible including 0
  3820. and -1. The output string is blank padded to 16 characters to make the name look like a netbios
  3821. name.
  3822. The string representation is in ANSI, not UNICODE.
  3823. The caller must allocate the storage, which should be 16 characters.
  3824. Arguments:
  3825. Address - IP address in network byte order
  3826. Buffer - Pointer to buffer to receive string representation, ANSI
  3827. Return Value:
  3828. void
  3829. --*/
  3830. {
  3831. ULONG i;
  3832. UCHAR byte, c0, c1, c2;
  3833. PCHAR p = Buffer;
  3834. for( i = 0; i < 4; i++ )
  3835. {
  3836. byte = (UCHAR) (Address & 0xff);
  3837. c0 = byte % 10;
  3838. byte /= 10;
  3839. c1 = byte % 10;
  3840. byte /= 10;
  3841. c2 = byte;
  3842. if (c2 != 0)
  3843. {
  3844. *p++ = c2 + '0';
  3845. *p++ = c1 + '0';
  3846. } else if (c1 != 0)
  3847. {
  3848. *p++ = c1 + '0';
  3849. }
  3850. *p++ = c0 + '0';
  3851. if (i != 3)
  3852. *p++ = '.';
  3853. Address >>= 8;
  3854. }
  3855. // space pad up to 16 characters
  3856. while (p < (Buffer + 16))
  3857. {
  3858. *p++ = ' ';
  3859. }
  3860. } // Inet_ntoa1
  3861. //----------------------------------------------------------------------------
  3862. NTSTATUS
  3863. PerformInboundProcessing(
  3864. tDEVICECONTEXT *pDeviceContext,
  3865. tLOWERCONNECTION *pLowerConn,
  3866. PTA_IP_ADDRESS pIpAddress
  3867. )
  3868. /*++
  3869. Routine Description:
  3870. This routine is called by the connection handler to force the state machine through a session
  3871. establishment even though no message has been received. We create a session request and feed
  3872. it into Inbound processing. Inbound will find the listening consumer and give him a chance to
  3873. accept.
  3874. Arguments:
  3875. pDeviceContext -
  3876. pLowerConn -
  3877. pIpAddress - Ip address of the source of the connect request
  3878. Return Value:
  3879. NTSTATUS -
  3880. --*/
  3881. {
  3882. ULONG status;
  3883. ULONG BytesTaken;
  3884. USHORT sLength;
  3885. tSESSIONREQ *pSessionReq = NULL;
  3886. PUCHAR pCopyTo;
  3887. CHAR SourceName[16];
  3888. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3889. KdPrint(("Nbt.TdiConnectHandler: skipping session setup\n"));
  3890. if (pIpAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)
  3891. {
  3892. return STATUS_INVALID_ADDRESS_COMPONENT;
  3893. }
  3894. Inet_ntoa_nb( pIpAddress->Address[0].Address[0].in_addr, SourceName );
  3895. // the length is the 4 byte session hdr length + the half ascii calling
  3896. // and called names + the scope length times 2, one for each name
  3897. //
  3898. sLength = (USHORT) (sizeof(tSESSIONREQ) + (NETBIOS_NAME_SIZE << 2) + (NbtConfig.ScopeLength <<1));
  3899. pSessionReq = (tSESSIONREQ *)NbtAllocMem(sLength,NBT_TAG('G'));
  3900. if (!pSessionReq)
  3901. {
  3902. NbtTrace(NBT_TRACE_INBOUND, ("Out of resource for %!ipaddr!:%d",
  3903. pIpAddress->Address[0].Address[0].in_addr, pIpAddress->Address[0].Address[0].sin_port));
  3904. return STATUS_INSUFFICIENT_RESOURCES;
  3905. }
  3906. pSessionReq->Hdr.Type = NBT_SESSION_REQUEST;
  3907. pSessionReq->Hdr.Flags = NBT_SESSION_FLAGS;
  3908. pSessionReq->Hdr.Length = (USHORT)htons(sLength- (USHORT)sizeof(tSESSIONHDR)); // size of called and calling NB names.
  3909. // put the Dest HalfAscii name into the Session Pdu
  3910. pCopyTo = ConvertToHalfAscii( (PCHAR)&pSessionReq->CalledName.NameLength,
  3911. pDeviceContext->MessageEndpoint,
  3912. NbtConfig.pScope,
  3913. NbtConfig.ScopeLength);
  3914. // put the Source HalfAscii name into the Session Pdu
  3915. pCopyTo = ConvertToHalfAscii(pCopyTo,
  3916. SourceName,
  3917. NbtConfig.pScope,
  3918. NbtConfig.ScopeLength);
  3919. // Inbound expects this lock to be held!
  3920. CTESpinLockAtDpc(pLowerConn);
  3921. status = Inbound(
  3922. NULL, // ReceiveEventContext - not used
  3923. pLowerConn, // ConnectionContext
  3924. 0, // ReceiveFlags - not used
  3925. sLength, // BytesIndicated
  3926. sLength, // BytesAvailable - not used
  3927. &BytesTaken, // BytesTaken
  3928. pSessionReq, // pTsdu
  3929. NULL // RcvBuffer
  3930. );
  3931. CTESpinFreeAtDpc(pLowerConn);
  3932. if (!NT_SUCCESS(status)) {
  3933. NbtTrace(NBT_TRACE_INBOUND, ("Inbound() returns %!status! for %!ipaddr!:%d %!NBTNAME!<%02x>",
  3934. status, pIpAddress->Address[0].Address[0].in_addr,
  3935. pIpAddress->Address[0].Address[0].sin_port, pCopyTo, (unsigned)pCopyTo[15]));
  3936. }
  3937. CTEMemFree( pSessionReq );
  3938. return status;
  3939. } // PerformInboundProcessing
  3940. #endif
  3941. //----------------------------------------------------------------------------
  3942. NTSTATUS
  3943. AcceptCompletionRoutine(
  3944. IN PDEVICE_OBJECT DeviceObject,
  3945. IN PIRP pIrp,
  3946. IN PVOID pContext
  3947. )
  3948. /*++
  3949. Routine Description:
  3950. This routine handles the completion of an Accept to the transport.
  3951. Arguments:
  3952. Return Value:
  3953. NTSTATUS - success or not
  3954. --*/
  3955. {
  3956. tLOWERCONNECTION *pLowerConn;
  3957. CTELockHandle OldIrq;
  3958. tDEVICECONTEXT *pDeviceContext;
  3959. pLowerConn = (tLOWERCONNECTION *)pContext;
  3960. pDeviceContext = pLowerConn->pDeviceContext;
  3961. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  3962. CTESpinLockAtDpc(pDeviceContext);
  3963. CTESpinLockAtDpc(pLowerConn);
  3964. //
  3965. // if the connection disconnects before the connect accept irp (this irp)
  3966. // completes do not put back on the free list here but let nbtdisconnect
  3967. // handle it.
  3968. // (i.e if the state is no longer INBOUND, then don't touch the connection
  3969. //
  3970. NbtTrace(NBT_TRACE_INBOUND, ("TDI_ACCEPT pIrp %p: pLowerConn %p %!status!",
  3971. pIrp, pLowerConn, pIrp->IoStatus.Status));
  3972. #ifdef _NETBIOSLESS
  3973. if (!NT_SUCCESS(pIrp->IoStatus.Status))
  3974. {
  3975. if (pLowerConn->State == NBT_SESSION_INBOUND)
  3976. {
  3977. #else
  3978. if ((!NT_SUCCESS(pIrp->IoStatus.Status)) &&
  3979. (pLowerConn->State == NBT_SESSION_INBOUND))
  3980. {
  3981. #endif
  3982. //
  3983. // the accept failed, so close the connection and create
  3984. // a new one to be sure all activity is run down on the connection.
  3985. //
  3986. //
  3987. // Previously, the LowerConnection was in the SESSION_INBOUND state
  3988. // hence we have to remove it from the WaitingForInbound Q and put
  3989. // it on the active LowerConnection list!
  3990. //
  3991. RemoveEntryList (&pLowerConn->Linkage);
  3992. InsertTailList (&pLowerConn->pDeviceContext->LowerConnection, &pLowerConn->Linkage);
  3993. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  3994. //
  3995. // Change the RefCount Context to Connected!
  3996. //
  3997. NBT_SWAP_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, REF_LOWC_CONNECTED, TRUE);
  3998. InterlockedDecrement (&pLowerConn->pDeviceContext->NumWaitingForInbound);
  3999. CTESpinFreeAtDpc(pLowerConn);
  4000. CTESpinFreeAtDpc(pDeviceContext);
  4001. KdPrint(("Nbt.AcceptCompletionRoutine: error: %lx\n", pIrp->IoStatus.Status));
  4002. if (!NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT))
  4003. {
  4004. pDeviceContext = NULL;
  4005. }
  4006. NTQueueToWorkerThread(
  4007. &pLowerConn->WorkItemCleanUpAndWipeOut,
  4008. DelayedCleanupAfterDisconnect,
  4009. NULL,
  4010. pLowerConn,
  4011. NULL,
  4012. pDeviceContext,
  4013. TRUE
  4014. );
  4015. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4016. #ifdef _NETBIOSLESS
  4017. }
  4018. else if (pLowerConn->State == NBT_SESSION_UP)
  4019. {
  4020. NTSTATUS status;
  4021. // We are in message only mode and we need to clean up because the client rejected
  4022. // the accept for some reason. We are in the UP state so we need to do a heavy
  4023. // duty cleanup.
  4024. ASSERT( IsDeviceNetbiosless(pLowerConn->pDeviceContext) );
  4025. CTESpinFreeAtDpc(pLowerConn);
  4026. CTESpinFreeAtDpc(pDeviceContext);
  4027. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4028. KdPrint(("Nbt.AcceptCompletionRoutine: Message only error: %lx\n", pIrp->IoStatus.Status));
  4029. NbtTrace(NBT_TRACE_INBOUND, ("Message only error: %!status!", pIrp->IoStatus.Status));
  4030. // this call will indicate the disconnect to the client and clean up abit.
  4031. //
  4032. status = DisconnectHndlrNotOs (NULL,
  4033. (PVOID)pLowerConn,
  4034. 0,
  4035. NULL,
  4036. 0,
  4037. NULL,
  4038. TDI_DISCONNECT_ABORT);
  4039. }
  4040. else
  4041. {
  4042. // Already disconnected
  4043. CTESpinFreeAtDpc(pLowerConn);
  4044. CTESpinFreeAtDpc(pDeviceContext);
  4045. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4046. }
  4047. #endif
  4048. }
  4049. else
  4050. {
  4051. CTESpinFreeAtDpc(pLowerConn);
  4052. CTESpinFreeAtDpc(pDeviceContext);
  4053. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4054. }
  4055. NbtFreeIrp(pIrp);
  4056. // return this status to stop the IO subsystem from further processing the
  4057. // IRP - i.e. trying to complete it back to the initiating thread! -since
  4058. // there is not initiating thread - we are the initiator
  4059. return(STATUS_MORE_PROCESSING_REQUIRED);
  4060. }
  4061. //----------------------------------------------------------------------------
  4062. NTSTATUS
  4063. TdiDisconnectHandler (
  4064. IN PVOID EventContext,
  4065. IN PVOID ConnectionContext,
  4066. IN ULONG DisconnectDataLength,
  4067. IN PVOID pDisconnectData,
  4068. IN ULONG DisconnectInformationLength,
  4069. IN PVOID pDisconnectInformation,
  4070. IN ULONG DisconnectIndicators
  4071. )
  4072. /*++
  4073. Routine Description:
  4074. This routine is called when a session is disconnected from a remote
  4075. machine.
  4076. Arguments:
  4077. IN PVOID EventContext,
  4078. IN PCONNECTION_CONTEXT ConnectionContext,
  4079. IN ULONG DisconnectDataLength,
  4080. IN PVOID DisconnectData,
  4081. IN ULONG DisconnectInformationLength,
  4082. IN PVOID DisconnectInformation,
  4083. IN ULONG DisconnectIndicators
  4084. Return Value:
  4085. NTSTATUS - Status of event indicator
  4086. --*/
  4087. {
  4088. NTSTATUS status;
  4089. tDEVICECONTEXT *pDeviceContext;
  4090. // convert the context value into the device context record ptr
  4091. pDeviceContext = (tDEVICECONTEXT *)EventContext;
  4092. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4093. KdPrint(("pDeviceContxt = %X ConnectEv = %X\n",pDeviceContext,ConnectionContext));
  4094. ASSERTMSG("Bad Device context passed to the Connection Event Handler",
  4095. pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
  4096. // call the non-OS specific routine to find a free connection.
  4097. status = DisconnectHndlrNotOs(
  4098. EventContext,
  4099. ConnectionContext,
  4100. DisconnectDataLength,
  4101. pDisconnectData,
  4102. DisconnectInformationLength,
  4103. pDisconnectInformation,
  4104. DisconnectIndicators);
  4105. if (!NT_SUCCESS(status))
  4106. {
  4107. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4108. KdPrint(("NO FREE CONNECTIONS in connect handler\n"));
  4109. return(STATUS_DATA_NOT_ACCEPTED);
  4110. }
  4111. return status;
  4112. }
  4113. //----------------------------------------------------------------------------
  4114. NTSTATUS
  4115. TdiRcvDatagramHandler(
  4116. IN PVOID pDgramEventContext,
  4117. IN int SourceAddressLength,
  4118. IN PVOID pSourceAddress,
  4119. IN int OptionsLength,
  4120. IN PVOID pOptions,
  4121. IN ULONG ReceiveDatagramFlags,
  4122. IN ULONG BytesIndicated,
  4123. IN ULONG BytesAvailable,
  4124. OUT ULONG *pBytesTaken,
  4125. IN PVOID pTsdu,
  4126. OUT PIRP *pIoRequestPacket
  4127. )
  4128. /*++
  4129. Routine Description:
  4130. This routine is the receive datagram event indication handler.
  4131. It is called when an Datagram arrives from the network, it will look for a
  4132. the address with an appropriate read datagram outstanding or a Datagrm
  4133. Event handler setup.
  4134. Arguments:
  4135. pDgramEventContext - Context provided for this event - pab
  4136. SourceAddressLength, - length of the src address
  4137. pSourceAddress, - src address
  4138. OptionsLength, - options length for the receive
  4139. pOptions, - options
  4140. BytesIndicated, - number of bytes this indication
  4141. BytesAvailable, - number of bytes in complete Tsdu
  4142. pTsdu - pointer to the datagram
  4143. Return Value:
  4144. *pBytesTaken - number of bytes used
  4145. *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
  4146. NTSTATUS - Status of receive operation
  4147. --*/
  4148. {
  4149. NTSTATUS status;
  4150. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
  4151. tDGRAMHDR UNALIGNED *pDgram = (tDGRAMHDR UNALIGNED *)pTsdu;
  4152. PIRP pIrp = NULL;
  4153. ULONG lBytesTaken;
  4154. tCLIENTLIST *pClientList;
  4155. CTELockHandle OldIrq;
  4156. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4157. KdPrint(( "NBT receive datagram handler pDeviceContext: %X\n",
  4158. pDeviceContext ));
  4159. *pIoRequestPacket = NULL;
  4160. ASSERTMSG("NBT:Invalid Device Context passed to DgramRcv Handler!!\n",
  4161. pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
  4162. // call a non-OS specific routine to decide what to do with the datagrams
  4163. pIrp = NULL;
  4164. pClientList = NULL;
  4165. status = DgramHndlrNotOs(
  4166. pDgramEventContext,
  4167. SourceAddressLength,
  4168. pSourceAddress,
  4169. OptionsLength,
  4170. pOptions,
  4171. ReceiveDatagramFlags,
  4172. BytesIndicated,
  4173. BytesAvailable,
  4174. &lBytesTaken,
  4175. pTsdu,
  4176. (PVOID *)&pIrp,
  4177. &pClientList);
  4178. if ( !NT_SUCCESS(status) )
  4179. {
  4180. // fail the request back to the transport provider since we
  4181. // could not find a receive buffer or receive handler or the
  4182. // data was taken in the indication handler.
  4183. //
  4184. return(STATUS_DATA_NOT_ACCEPTED);
  4185. }
  4186. else
  4187. {
  4188. // a rcv buffer was returned, so use it for the receive.(an Irp)
  4189. PTDI_REQUEST_KERNEL_RECEIVEDG pParams;
  4190. PIO_STACK_LOCATION pIrpSp;
  4191. ULONG lRcvLength;
  4192. ULONG lRcvFlags;
  4193. // When the client list is returned, we need to make up an irp to
  4194. // send down to the transport, which we will use in the completion
  4195. // routine to copy the data to all clients, ONLY if we are not
  4196. // using a client buffer, so check that flag first.
  4197. //
  4198. if (pClientList && !pClientList->fUsingClientBuffer)
  4199. {
  4200. PMDL pMdl;
  4201. PVOID pBuffer;
  4202. //
  4203. // get an irp to do the receive with and attach
  4204. // a buffer to it.
  4205. //
  4206. while (1)
  4207. {
  4208. if (NT_SUCCESS(GetIrp(&pIrp)))
  4209. {
  4210. if (pBuffer = NbtAllocMem (BytesAvailable, NBT_TAG('t')))
  4211. {
  4212. if (pMdl = IoAllocateMdl (pBuffer, BytesAvailable, FALSE, FALSE, NULL))
  4213. {
  4214. break;
  4215. }
  4216. KdPrint(("Nbt.TdiRcvDatagramHandler: Unable to IoAllocateMdl, Kill Connection\n"));
  4217. CTEMemFree(pBuffer);
  4218. }
  4219. else
  4220. {
  4221. KdPrint(("Nbt.TdiRcvDatagramHandler: Unable to allocate Buffer, Kill Connection\n"));
  4222. }
  4223. NbtFreeIrp(pIrp);
  4224. }
  4225. else
  4226. {
  4227. KdPrint(("Nbt.TdiRcvDatagramHandler: Unable to GetIrp, Kill Connection\n"));
  4228. }
  4229. if (!pClientList->fProxy)
  4230. {
  4231. //
  4232. // We failed, so Dereference the Client + Address we had
  4233. // reference earlier for multiple clients
  4234. //
  4235. NBT_DEREFERENCE_CLIENT (pClientList->pClientEle);
  4236. NBT_DEREFERENCE_ADDRESS (pClientList->pAddress, REF_ADDR_MULTICLIENTS);
  4237. CTEMemFree(pClientList->pRemoteAddress);
  4238. }
  4239. CTEMemFree(pClientList);
  4240. return (STATUS_DATA_NOT_ACCEPTED);
  4241. }
  4242. // Map the pages in memory...
  4243. MmBuildMdlForNonPagedPool(pMdl);
  4244. pIrp->MdlAddress = pMdl;
  4245. lRcvFlags = 0;
  4246. lRcvLength = BytesAvailable;
  4247. }
  4248. else
  4249. {
  4250. ASSERT(pIrp);
  4251. // *TODO* may have to keep track of the case where the
  4252. // client returns a buffer that is not large enough for all of the
  4253. // data indicated. So the next posting of a buffer gets passed
  4254. // directly to the transport.
  4255. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4256. lRcvFlags = ((PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters)->ReceiveFlags;
  4257. lRcvLength = ((PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters)->ReceiveLength;
  4258. if (lRcvLength < BytesIndicated - lBytesTaken)
  4259. {
  4260. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4261. KdPrint(("Nbt:Clients Buffer is too short on Rcv Dgram size= %X, needed = %X\n",
  4262. lRcvLength, BytesIndicated-lBytesTaken));
  4263. }
  4264. }
  4265. // this code is sped up somewhat by expanding the code here rather than calling
  4266. // the TdiBuildReceive macro
  4267. // make the next stack location the current one. Normally IoCallDriver
  4268. // would do this but we are not going through IoCallDriver here, since the
  4269. // Irp is just passed back with RcvIndication.
  4270. ASSERT(pIrp->CurrentLocation > 1);
  4271. IoSetNextIrpStackLocation(pIrp);
  4272. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4273. pIrpSp->CompletionRoutine = CompletionRcvDgram;
  4274. // pass the ClientList to the completion routine so it can
  4275. // copy the datagram to several clients that may be listening on the
  4276. // same name
  4277. //
  4278. pIrpSp->Context = (PVOID)pClientList;
  4279. CHECK_PTR(pIrpSp);
  4280. pIrpSp->Flags = 0;
  4281. // set flags so the completion routine is always invoked.
  4282. pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
  4283. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  4284. pIrpSp->MinorFunction = TDI_RECEIVE_DATAGRAM;
  4285. //
  4286. // Verify that we have a valid Device and FileObject for TcpIp below
  4287. //
  4288. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4289. if (pDeviceContext->pFileObjects)
  4290. {
  4291. pIrpSp->DeviceObject = pDeviceContext->pFileObjects->pDgramDeviceObject;
  4292. pIrpSp->FileObject = pDeviceContext->pFileObjects->pDgramFileObject;
  4293. }
  4294. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4295. pParams = (PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters;
  4296. pParams->ReceiveFlags = lRcvFlags;
  4297. pParams->ReceiveLength = lRcvLength;
  4298. // pass back the irp to the transport provider and increment the stack
  4299. // location so it can write to the irp if it needs to.
  4300. *pIoRequestPacket = pIrp;
  4301. *pBytesTaken = lBytesTaken;
  4302. return(STATUS_MORE_PROCESSING_REQUIRED);
  4303. }
  4304. //
  4305. // Transport will complete the processing of the request, we don't
  4306. // want the datagram.
  4307. //
  4308. IF_DBG (NBT_DEBUG_TDIHNDLR)
  4309. KdPrint(( "NBT receive datagram handler ignored receive, pDeviceContext: %X\n",
  4310. pDeviceContext ));
  4311. return STATUS_DATA_NOT_ACCEPTED;
  4312. // to keep the compiler from generating warnings...
  4313. UNREFERENCED_PARAMETER( SourceAddressLength );
  4314. UNREFERENCED_PARAMETER( BytesIndicated );
  4315. UNREFERENCED_PARAMETER( BytesAvailable );
  4316. UNREFERENCED_PARAMETER( pBytesTaken );
  4317. UNREFERENCED_PARAMETER( pTsdu );
  4318. UNREFERENCED_PARAMETER( OptionsLength );
  4319. UNREFERENCED_PARAMETER( pOptions );
  4320. }
  4321. //----------------------------------------------------------------------------
  4322. NTSTATUS
  4323. TdiRcvNameSrvHandler(
  4324. IN PVOID pDgramEventContext,
  4325. IN int SourceAddressLength,
  4326. IN PVOID pSourceAddress,
  4327. IN int OptionsLength,
  4328. IN PVOID pOptions,
  4329. IN ULONG ReceiveDatagramFlags,
  4330. IN ULONG BytesIndicated,
  4331. IN ULONG BytesAvailable,
  4332. OUT ULONG *pBytesTaken,
  4333. IN PVOID pTsdu,
  4334. OUT PIRP *pIoRequestPacket
  4335. )
  4336. /*++
  4337. Routine Description:
  4338. This routine is the Name Service datagram event indication handler.
  4339. It gets all datagrams destined for UDP port 137
  4340. Arguments:
  4341. pDgramEventContext - Context provided for this event - pab
  4342. SourceAddressLength, - length of the src address
  4343. pSourceAddress, - src address
  4344. OptionsLength, - options length for the receive
  4345. pOptions, - options
  4346. BytesIndicated, - number of bytes this indication
  4347. BytesAvailable, - number of bytes in complete Tsdu
  4348. pTsdu - pointer to the datagram
  4349. Return Value:
  4350. *pBytesTaken - number of bytes used
  4351. *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
  4352. NTSTATUS - Status of receive operation
  4353. --*/
  4354. {
  4355. NTSTATUS status;
  4356. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
  4357. tNAMEHDR UNALIGNED *pNameSrv = (tNAMEHDR UNALIGNED *)pTsdu;
  4358. USHORT OpCode;
  4359. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4360. KdPrint(( "NBT: NAMEHDR datagram handler pDeviceContext: %X\n",
  4361. pDeviceContext ));
  4362. *pIoRequestPacket = NULL;
  4363. //
  4364. // check if the whole datagram has arrived yet
  4365. //
  4366. if (BytesIndicated != BytesAvailable)
  4367. {
  4368. PIRP pIrp;
  4369. PVOID pBuffer;
  4370. PMDL pMdl;
  4371. ULONG Length;
  4372. //
  4373. // get an irp to do the receive with and attach
  4374. // a buffer to it.
  4375. //
  4376. status = GetIrp(&pIrp);
  4377. if (!NT_SUCCESS(status))
  4378. {
  4379. return(STATUS_DATA_NOT_ACCEPTED);
  4380. }
  4381. //
  4382. // make an Mdl for a buffer to get all of the data from
  4383. // the transprot
  4384. //
  4385. Length = BytesAvailable + SourceAddressLength + sizeof(ULONG);
  4386. Length = ((Length + 3)/sizeof(ULONG)) * sizeof(ULONG);
  4387. pBuffer = NbtAllocMem(Length,NBT_TAG('u'));
  4388. if (pBuffer)
  4389. {
  4390. PVOID pSrcAddr;
  4391. //
  4392. // save the source address and length in the buffer for later
  4393. // indication back to this routine.
  4394. //
  4395. *(ULONG UNALIGNED *)((PUCHAR)pBuffer + BytesAvailable) = SourceAddressLength;
  4396. pSrcAddr = (PVOID)((PUCHAR)pBuffer + BytesAvailable + sizeof(ULONG));
  4397. CTEMemCopy(pSrcAddr,
  4398. pSourceAddress,
  4399. SourceAddressLength);
  4400. // Allocate a MDL and set the header sizes correctly
  4401. pMdl = IoAllocateMdl(
  4402. pBuffer,
  4403. BytesAvailable,
  4404. FALSE,
  4405. FALSE,
  4406. NULL);
  4407. if (pMdl)
  4408. {
  4409. // Map the pages in memory...
  4410. MmBuildMdlForNonPagedPool(pMdl);
  4411. pIrp->MdlAddress = pMdl;
  4412. ASSERT(pDeviceContext);
  4413. //
  4414. // Build a Datagram Receive Irp (as opposed to a Connect Receive Irp)
  4415. // Bug# 125816
  4416. //
  4417. TdiBuildReceiveDatagram(
  4418. pIrp,
  4419. &pDeviceContext->DeviceObject,
  4420. pDeviceContext->pFileObjects->pNameServerFileObject,
  4421. NameSrvCompletionRoutine,
  4422. ULongToPtr(BytesAvailable),
  4423. pMdl,
  4424. BytesAvailable,
  4425. NULL,
  4426. NULL,
  4427. (ULONG)TDI_RECEIVE_NORMAL);
  4428. *pBytesTaken = 0;
  4429. *pIoRequestPacket = pIrp;
  4430. // make the next stack location the current one. Normally IoCallDriver
  4431. // would do this but we are not going through IoCallDriver here, since the
  4432. // Irp is just passed back with RcvIndication.
  4433. //
  4434. ASSERT(pIrp->CurrentLocation > 1);
  4435. IoSetNextIrpStackLocation(pIrp);
  4436. return(STATUS_MORE_PROCESSING_REQUIRED);
  4437. }
  4438. CTEMemFree(pBuffer);
  4439. }
  4440. NbtFreeIrp(pIrp);
  4441. return(STATUS_DATA_NOT_ACCEPTED);
  4442. }
  4443. //
  4444. // Bug# 125279: Ensure that we have received enough data to be able to
  4445. // read most data fields
  4446. if (BytesIndicated < NBT_MINIMUM_QUERY) // should this be limited to 12 ?
  4447. {
  4448. KdPrint (("Nbt.TdiRcvNameSrvHandler: WARNING!!! Rejecting Request -- BytesIndicated=<%d> < <%d>\n",
  4449. BytesIndicated, NBT_MINIMUM_QUERY));
  4450. return(STATUS_DATA_NOT_ACCEPTED);
  4451. }
  4452. if (pWinsInfo)
  4453. {
  4454. USHORT TransactionId;
  4455. ULONG SrcAddress;
  4456. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&((PTRANSPORT_ADDRESS)pSourceAddress)->Address[0].Address[0])->in_addr);
  4457. //
  4458. // Pass To Wins if:
  4459. //
  4460. // 1) It is a response pdu with the transaction id in the WINS range
  4461. // that is not a WACK... OR
  4462. // 2) It is a request that is NOT broadcast....and...
  4463. // 2) It is a name query(excluding node status requests),
  4464. // Allowing queries from other netbt clients
  4465. // allowing queries from anyone not on this machine OR
  4466. // 3) It is a name release request. OR
  4467. // 4) It is a name refresh OR
  4468. // 5) It is a name registration
  4469. //
  4470. OpCode = pNameSrv->OpCodeFlags;
  4471. TransactionId = ntohs(pNameSrv->TransactId);
  4472. if (((OpCode & OP_RESPONSE) && (TransactionId <= WINS_MAXIMUM_TRANSACTION_ID) && (OpCode != OP_WACK))
  4473. ||
  4474. ((!(OpCode & (OP_RESPONSE | FL_BROADCAST)))
  4475. &&
  4476. ((((OpCode & NM_FLAGS_MASK) == OP_QUERY) &&
  4477. (OpCode & FL_RECURDESIRE) && // not node status request
  4478. ((TransactionId > WINS_MAXIMUM_TRANSACTION_ID) || (!SrcIsUs(SrcAddress))))
  4479. ||
  4480. (OpCode & (OP_RELEASE | OP_REFRESH))
  4481. ||
  4482. (OpCode & OP_REGISTRATION))))
  4483. {
  4484. status = PassNamePduToWins(
  4485. pDeviceContext,
  4486. pSourceAddress,
  4487. pNameSrv,
  4488. BytesIndicated);
  4489. // NbtConfig.DgramBytesRcvd += BytesIndicated;
  4490. //
  4491. // if WINS took the data then tell the transport to dump the data
  4492. // since we have buffered it already. Otherwise, let nbt take
  4493. // a look at the data
  4494. //
  4495. if (NT_SUCCESS(status))
  4496. {
  4497. return(STATUS_DATA_NOT_ACCEPTED);
  4498. }
  4499. }
  4500. }
  4501. // DO a quick check of the name to see if it is in the local name table
  4502. // and reject it otherwise - for name queries only, if not the proxy
  4503. //
  4504. if (!(NodeType & PROXY))
  4505. {
  4506. ULONG UNALIGNED *pHdr;
  4507. ULONG i,lValue;
  4508. UCHAR pNameStore[NETBIOS_NAME_SIZE];
  4509. UCHAR *pName;
  4510. tNAMEADDR *pNameAddr;
  4511. CTELockHandle OldIrq;
  4512. // it must be a name query request, not a response, and not a
  4513. // node status request, to enter this special check
  4514. //
  4515. OpCode = pNameSrv->OpCodeFlags;
  4516. if (((OpCode & NM_FLAGS_MASK) == OP_QUERY) &&
  4517. (!(OpCode & OP_RESPONSE)) &&
  4518. (OpCode & FL_RECURDESIRE)) // not node status request
  4519. {
  4520. pHdr = (ULONG UNALIGNED *)pNameSrv->NameRR.NetBiosName;
  4521. pName = pNameStore;
  4522. // the Half Ascii portion of the netbios name is always 32 bytes long
  4523. for (i=0; i < NETBIOS_NAME_SIZE*2 ;i +=4 )
  4524. {
  4525. lValue = *pHdr - 0x41414141; // four A's
  4526. pHdr++;
  4527. lValue = ((lValue & 0x0F000000) >> 16) +
  4528. ((lValue & 0x0F0000) >> 4) +
  4529. ((lValue & 0x0F00) >> 8) +
  4530. ((lValue & 0x0F) << 4);
  4531. *(PUSHORT)pName = (USHORT)lValue;
  4532. ((PUSHORT)pName)++;
  4533. }
  4534. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4535. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  4536. pNameStore,
  4537. NULL,
  4538. &pNameAddr);
  4539. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4540. if (!NT_SUCCESS(status))
  4541. {
  4542. *pBytesTaken = BytesIndicated;
  4543. return(STATUS_DATA_NOT_ACCEPTED);
  4544. }
  4545. }
  4546. }
  4547. ASSERT(pDeviceContext);
  4548. // call a non-OS specific routine to decide what to do with the datagrams
  4549. status = NameSrvHndlrNotOs(
  4550. pDeviceContext,
  4551. pSourceAddress,
  4552. pNameSrv,
  4553. BytesIndicated,
  4554. (BOOLEAN)((ReceiveDatagramFlags & TDI_RECEIVE_BROADCAST) != 0));
  4555. // NbtConfig.DgramBytesRcvd += BytesIndicated
  4556. return status;
  4557. // to keep the compiler from generating warnings...
  4558. UNREFERENCED_PARAMETER( SourceAddressLength );
  4559. UNREFERENCED_PARAMETER( BytesIndicated );
  4560. UNREFERENCED_PARAMETER( BytesAvailable );
  4561. UNREFERENCED_PARAMETER( pBytesTaken );
  4562. UNREFERENCED_PARAMETER( pTsdu );
  4563. UNREFERENCED_PARAMETER( OptionsLength );
  4564. UNREFERENCED_PARAMETER( pOptions );
  4565. }
  4566. //----------------------------------------------------------------------------
  4567. NTSTATUS
  4568. NameSrvCompletionRoutine(
  4569. IN PDEVICE_OBJECT DeviceObject,
  4570. IN PIRP pIrp,
  4571. IN PVOID Context
  4572. )
  4573. /*++
  4574. Routine Description:
  4575. This routine handles the case when a name service datagram is too
  4576. short and and Irp has to be passed back to the transport to get the
  4577. rest of the datagram. The irp completes through here when full.
  4578. Arguments:
  4579. DeviceObject - unused.
  4580. Irp - Supplies Irp that the transport has finished processing.
  4581. Context - Supplies the pConnectEle - the connection data structure
  4582. Return Value:
  4583. The final status from the operation (success or an exception).
  4584. --*/
  4585. {
  4586. NTSTATUS status;
  4587. PIRP pIoRequestPacket;
  4588. ULONG BytesTaken;
  4589. ULONG Offset = PtrToUlong(Context);
  4590. PVOID pBuffer;
  4591. ULONG SrcAddressLength;
  4592. PVOID pSrcAddress;
  4593. IF_DBG (NBT_DEBUG_TDIHNDLR)
  4594. KdPrint(("NameSrvCompletionRoutine pRcvBuffer: %X, Status: %X Length %X\n",
  4595. Context, pIrp->IoStatus.Status, pIrp->IoStatus.Information));
  4596. if (pBuffer = MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority))
  4597. {
  4598. SrcAddressLength = *(ULONG UNALIGNED *)((PUCHAR)pBuffer + Offset);
  4599. pSrcAddress = (PVOID)((PUCHAR)pBuffer + Offset + sizeof(ULONG));
  4600. if (!DeviceObject)
  4601. {
  4602. DeviceObject = (IoGetNextIrpStackLocation (pIrp))->DeviceObject;
  4603. }
  4604. //
  4605. // just call the regular indication routine as if UDP had done it.
  4606. //
  4607. TdiRcvNameSrvHandler (DeviceObject,
  4608. SrcAddressLength,
  4609. pSrcAddress,
  4610. 0,
  4611. NULL,
  4612. TDI_RECEIVE_NORMAL,
  4613. (ULONG) pIrp->IoStatus.Information,
  4614. (ULONG) pIrp->IoStatus.Information,
  4615. &BytesTaken,
  4616. pBuffer,
  4617. &pIoRequestPacket);
  4618. CTEMemFree (pBuffer);
  4619. }
  4620. //
  4621. // put our Irp back on its free list
  4622. //
  4623. IoFreeMdl (pIrp->MdlAddress);
  4624. NbtFreeIrp(pIrp);
  4625. return (STATUS_MORE_PROCESSING_REQUIRED);
  4626. }
  4627. //----------------------------------------------------------------------------
  4628. NTSTATUS
  4629. CompletionRcvDgram(
  4630. IN PDEVICE_OBJECT DeviceObject,
  4631. IN PIRP Irp,
  4632. IN PVOID Context
  4633. )
  4634. /*++
  4635. Routine Description:
  4636. This routine completes the Irp by removing the Rcv Element off the queue
  4637. and putting it back on the free list.
  4638. Arguments:
  4639. DeviceObject - unused.
  4640. Irp - Supplies Irp that the transport has finished processing.
  4641. Context - Supplies the pConnectEle - the connection data structure
  4642. Return Value:
  4643. The final status from the operation (success or an exception).
  4644. --*/
  4645. {
  4646. NTSTATUS status;
  4647. PLIST_ENTRY pHead;
  4648. PLIST_ENTRY pEntry;
  4649. PTA_NETBIOS_ADDRESS pRemoteAddress;
  4650. ULONG RemoteAddressLength;
  4651. ULONG BytesCopied;
  4652. PVOID pTsdu;
  4653. ULONG ReceiveFlags;
  4654. tCLIENTLIST *pClientList;
  4655. CTELockHandle OldIrq;
  4656. CTELockHandle OldIrq1;
  4657. ULONG ClientBytesTaken;
  4658. ULONG DataLength;
  4659. tADDRESSELE *pAddress;
  4660. tRCVELE *pRcvEle;
  4661. PLIST_ENTRY pRcvEntry;
  4662. tDEVICECONTEXT *pDeviceContext;
  4663. CTEULONGLONG AdapterMask;
  4664. IF_DBG (NBT_DEBUG_TDIHNDLR)
  4665. KdPrint(("CompletionRcvDgram pRcvBuffer: %X, Status: %X Length %X\n",
  4666. Context,
  4667. Irp->IoStatus.Status,
  4668. Irp->IoStatus.Information ));
  4669. // there may be several clients that want to see this datagram so check
  4670. // the client list to see...
  4671. //
  4672. if (Context)
  4673. {
  4674. tCLIENTELE *pClientPrev = NULL;
  4675. //
  4676. // Bug# 124683: Data may be invalid if Completion status was failure
  4677. //
  4678. if (NT_SUCCESS (Irp->IoStatus.Status))
  4679. {
  4680. DataLength = (ULONG)Irp->IoStatus.Information;
  4681. }
  4682. else
  4683. {
  4684. ASSERT (0);
  4685. DataLength = 0;
  4686. }
  4687. pTsdu = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, HighPagePriority);
  4688. pClientList = (tCLIENTLIST *) Context;
  4689. #ifdef PROXY_NODE
  4690. if (pClientList->fProxy)
  4691. {
  4692. //
  4693. // Call the ProxyDoDgramDist
  4694. //
  4695. status = ProxyDoDgramDist( pTsdu, DataLength,
  4696. (tNAMEADDR *)pClientList->pAddress, //NameAddr
  4697. pClientList->pRemoteAddress); //device context
  4698. }
  4699. else
  4700. #endif
  4701. {
  4702. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4703. // for the multihomed host, we only want to distribute the inbound
  4704. // datagram to clients on this same adapter, to avoid giving the
  4705. // datagram to the same client several times, once for each adapter
  4706. // it is bound to.
  4707. //
  4708. pDeviceContext = pClientList->pClientEle->pDeviceContext;
  4709. AdapterMask = pDeviceContext->AdapterMask;
  4710. pAddress = pClientList->pAddress;
  4711. pRemoteAddress = pClientList->pRemoteAddress;
  4712. RemoteAddressLength = pClientList->RemoteAddressLength;
  4713. ReceiveFlags = pClientList->ReceiveDatagramFlags;
  4714. //
  4715. // Since we will be traversing the ClientHead, lock
  4716. // the Address (we have already referenced the Address
  4717. // + Client in DgramRcvNotOs)
  4718. //
  4719. CTESpinLock(pAddress, OldIrq1);
  4720. pHead = &pClientList->pAddress->ClientHead;
  4721. pEntry = pHead->Flink;
  4722. if (!pClientList->fUsingClientBuffer)
  4723. {
  4724. while (pEntry != pHead)
  4725. {
  4726. PTDI_IND_RECEIVE_DATAGRAM EvRcvDgram;
  4727. PVOID RcvDgramEvContext;
  4728. tCLIENTELE *pClientEle;
  4729. PIRP pRcvIrp;
  4730. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  4731. // for multihomed hosts only distribute the datagram to
  4732. // clients hooked to this device context to avoid duplicate
  4733. // indications
  4734. //
  4735. if ((pClientEle->Verify == NBT_VERIFY_CLIENT) && // as opposed to CLIENT_DOWN!
  4736. (pClientEle->pDeviceContext->AdapterMask == AdapterMask))
  4737. {
  4738. EvRcvDgram = pClientEle->evRcvDgram;
  4739. RcvDgramEvContext = pClientEle->RcvDgramEvContext;
  4740. RemoteAddressLength = FIELD_OFFSET(TA_NETBIOS_ADDRESS,
  4741. Address[0].Address[0].NetbiosName[NETBIOS_NAME_SIZE]);
  4742. //
  4743. // Bug # 452211 -- since one of the clients may have the Extended
  4744. // addressing field set, set the # of addresses accordingly
  4745. //
  4746. if (pClientEle->ExtendedAddress)
  4747. {
  4748. pRemoteAddress->TAAddressCount = 2;
  4749. RemoteAddressLength += FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP);
  4750. }
  4751. else
  4752. {
  4753. pRemoteAddress->TAAddressCount = 1;
  4754. }
  4755. NBT_REFERENCE_CLIENT(pClientEle);
  4756. CTESpinFree(pAddress, OldIrq1);
  4757. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  4758. // dereference the previous client in the list
  4759. if (pClientPrev)
  4760. {
  4761. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4762. }
  4763. pClientPrev = pClientEle;
  4764. pRcvIrp = NULL;
  4765. ClientBytesTaken = 0;
  4766. status = (*EvRcvDgram) (RcvDgramEvContext,
  4767. RemoteAddressLength,
  4768. pRemoteAddress,
  4769. 0,
  4770. NULL,
  4771. #ifndef VXD
  4772. ReceiveFlags,
  4773. #endif
  4774. DataLength,
  4775. DataLength,
  4776. &ClientBytesTaken,
  4777. pTsdu,
  4778. &pRcvIrp);
  4779. if (!pRcvIrp)
  4780. {
  4781. // if no buffer is returned, then the client is done
  4782. // with the data so go to the next client ...since it may
  4783. // be possible to process all clients in this loop without
  4784. // ever sending an irp down to the transport
  4785. // free the remote address mem block
  4786. status = STATUS_DATA_NOT_ACCEPTED;
  4787. }
  4788. else
  4789. {
  4790. // the client has passed back an irp so
  4791. // copy the data to the client's Irp
  4792. //
  4793. TdiCopyBufferToMdl(pTsdu,
  4794. ClientBytesTaken,
  4795. DataLength - ClientBytesTaken,
  4796. pRcvIrp->MdlAddress,
  4797. 0,
  4798. &BytesCopied);
  4799. // length is copied length (since the MDL may be
  4800. // too short to take it all)
  4801. //
  4802. if (BytesCopied < (DataLength-ClientBytesTaken))
  4803. {
  4804. pRcvIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  4805. }
  4806. else
  4807. {
  4808. pRcvIrp->IoStatus.Status = STATUS_SUCCESS;
  4809. }
  4810. pRcvIrp->IoStatus.Information = BytesCopied;
  4811. IoCompleteRequest(pRcvIrp,IO_NETWORK_INCREMENT);
  4812. }
  4813. CTESpinLock(&NbtConfig.JointLock, OldIrq);
  4814. CTESpinLock(pAddress, OldIrq1);
  4815. }
  4816. // this code is protected from a client removing itself
  4817. // from the list of clients attached to an address by
  4818. // referencing the client prior to releasing the spin lock
  4819. // on the address. The client element does not get
  4820. // removed from the address list until its ref count goes
  4821. // to zero. We must hold the joint spin lock to prevent the
  4822. // next client from deleting itself from the list before we
  4823. // can increment its reference count.
  4824. //
  4825. pEntry = pEntry->Flink;
  4826. } // of while(pEntry != pHead)
  4827. }
  4828. else
  4829. {
  4830. // *** Client Has posted a receive Buffer, rather than using
  4831. // *** receive handler - VXD case!
  4832. // ***
  4833. while (pEntry != pHead)
  4834. {
  4835. tCLIENTELE *pClientEle;
  4836. PIRP pRcvIrp;
  4837. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  4838. // for multihomed hosts only distribute the datagram to
  4839. // clients hooked to this device context to avoid duplicate
  4840. // indications
  4841. //
  4842. if (pClientEle->pDeviceContext->AdapterMask == AdapterMask)
  4843. {
  4844. if (pClientEle == pClientList->pClientEle)
  4845. {
  4846. // this is the client whose buffer we are using - it is
  4847. // passed up to the client after all other clients
  4848. // have been processed.
  4849. //
  4850. pEntry = pEntry->Flink;
  4851. continue;
  4852. }
  4853. // check for datagrams posted to this name
  4854. //
  4855. if (!IsListEmpty(&pClientEle->RcvDgramHead))
  4856. {
  4857. pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
  4858. pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
  4859. pRcvIrp = pRcvEle->pIrp;
  4860. //
  4861. // copy the data to the client's Irp
  4862. //
  4863. TdiCopyBufferToMdl(pTsdu,
  4864. 0,
  4865. DataLength,
  4866. pRcvIrp->MdlAddress,
  4867. 0,
  4868. &BytesCopied);
  4869. // length is copied length (since the MDL may be too short to take it all)
  4870. if (BytesCopied < DataLength)
  4871. {
  4872. pRcvIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  4873. }
  4874. else
  4875. {
  4876. pRcvIrp->IoStatus.Status = STATUS_SUCCESS;
  4877. }
  4878. pRcvIrp->IoStatus.Information = BytesCopied;
  4879. //
  4880. // Increment the RefCount so that this Client hangs around!
  4881. //
  4882. NBT_REFERENCE_CLIENT (pClientEle);
  4883. CTESpinFree(pAddress, OldIrq1);
  4884. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  4885. //
  4886. // undo the InterlockedIncrement to the Previous client
  4887. //
  4888. if (pClientPrev)
  4889. {
  4890. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4891. }
  4892. pClientPrev = pClientEle;
  4893. IoCompleteRequest(pRcvIrp,IO_NETWORK_INCREMENT);
  4894. // free the receive block
  4895. CTEMemFree((PVOID)pRcvEle);
  4896. CTESpinLock(&NbtConfig.JointLock, OldIrq);
  4897. CTESpinLock(pAddress, OldIrq1);
  4898. }
  4899. pEntry = pEntry->Flink;
  4900. }
  4901. } // of while(pEntry != pHead)
  4902. CTESpinFree(pAddress, OldIrq1);
  4903. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  4904. // undo the InterlockedIncrement on the refcount
  4905. if (pClientPrev)
  4906. {
  4907. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4908. }
  4909. //
  4910. // The Client + Address were referenced in DgramRcvNotOs to be sure they did not
  4911. // disappear until this dgram rcv was done, which is now.
  4912. //
  4913. NBT_DEREFERENCE_CLIENT (pClientList->pClientEle); // Bug#: 124675
  4914. NBT_DEREFERENCE_ADDRESS (pClientList->pAddress, REF_ADDR_MULTICLIENTS);
  4915. // free the remote address structure and the client list
  4916. // allocated in DgramHndlrNotOs
  4917. //
  4918. CTEMemFree (pClientList->pRemoteAddress);
  4919. CTEMemFree (pClientList);
  4920. // returning success allows the IO subsystem to complete the
  4921. // irp that we used to get the data - i.e. one client's
  4922. // buffer
  4923. //
  4924. return(STATUS_SUCCESS);
  4925. }
  4926. CTESpinFree(pAddress, OldIrq1);
  4927. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4928. // dereference the previous client in the list from the RcvHANDLER
  4929. // case a page or so above...
  4930. //
  4931. if (pClientPrev)
  4932. {
  4933. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4934. }
  4935. //
  4936. // The Client + Address were referenced in DgramRcvNotOs to be sure they did not
  4937. // disappear until this dgram rcv was done, which is now.
  4938. //
  4939. NBT_DEREFERENCE_CLIENT (pClientList->pClientEle); // Bug#: 124675
  4940. NBT_DEREFERENCE_ADDRESS (pClientList->pAddress, REF_ADDR_MULTICLIENTS);
  4941. }
  4942. //
  4943. // Free the buffers allocated
  4944. //
  4945. if (!pClientList->fProxy)
  4946. {
  4947. CTEMemFree (pClientList->pRemoteAddress);
  4948. }
  4949. CTEMemFree (pClientList);
  4950. CTEMemFree(pTsdu);
  4951. //
  4952. // Free the Mdl + put the Irp back on its free list
  4953. //
  4954. IF_DBG(NBT_DEBUG_RCV)
  4955. KdPrint(("****Freeing Mdl: Irp = %X Mdl = %X\n",Irp,Irp->MdlAddress));
  4956. IoFreeMdl(Irp->MdlAddress);
  4957. NbtFreeIrp(Irp);
  4958. return(STATUS_MORE_PROCESSING_REQUIRED);
  4959. }
  4960. // for the single receive case this passes the rcv up to the client
  4961. //
  4962. return(STATUS_SUCCESS);
  4963. UNREFERENCED_PARAMETER( DeviceObject );
  4964. }
  4965. //----------------------------------------------------------------------------
  4966. NTSTATUS
  4967. TdiErrorHandler (
  4968. IN PVOID Context,
  4969. IN NTSTATUS Status
  4970. )
  4971. /*++
  4972. Routine Description:
  4973. This routine is called on any error indications passed back from the
  4974. transport. It implements LAN_STATUS_ALERT.
  4975. Arguments:
  4976. Context - Supplies the pfcb for the address.
  4977. Status - Supplies the error.
  4978. Return Value:
  4979. NTSTATUS - Status of event indication
  4980. --*/
  4981. {
  4982. #ifdef _NETBIOSLESS
  4983. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)Context;
  4984. // If NB-full trys to contact NB-less host, we may get this error
  4985. if ( (Status == STATUS_PORT_UNREACHABLE) ||
  4986. (Status == STATUS_HOST_UNREACHABLE))
  4987. {
  4988. return(STATUS_DATA_NOT_ACCEPTED);
  4989. }
  4990. // TODO: Log a message here
  4991. KdPrint(("Nbt.TdiErrorHandler: TDI error event notification\n\tDevice %x\n\tStatus: 0x%x\n",
  4992. pDeviceContext, Status));
  4993. #else
  4994. KdPrint(("Nbt.TdiErrorHandler: Error Event HAndler hit unexpectedly\n"));
  4995. #endif
  4996. return(STATUS_DATA_NOT_ACCEPTED);
  4997. }
  4998. //----------------------------------------------------------------------------
  4999. VOID
  5000. SumMdlLengths (
  5001. IN PMDL pMdl,
  5002. IN ULONG BytesCopied,
  5003. IN tCONNECTELE *pConnectEle
  5004. )
  5005. /*++
  5006. Routine Description:
  5007. This routine is called to sum the lengths of MDLs in a chain.
  5008. Arguments:
  5009. Return Value:
  5010. NTSTATUS - Status of event indication
  5011. --*/
  5012. {
  5013. ULONG TotalLength;
  5014. TotalLength = 0;
  5015. do
  5016. {
  5017. if ((TotalLength + MmGetMdlByteCount(pMdl)) > BytesCopied)
  5018. {
  5019. pConnectEle->OffsetFromStart = BytesCopied - TotalLength;
  5020. pConnectEle->pNextMdl = pMdl;
  5021. break;
  5022. }
  5023. else
  5024. {
  5025. TotalLength += MmGetMdlByteCount(pMdl);
  5026. }
  5027. }
  5028. while (pMdl=(PMDL)pMdl->Next);
  5029. return;
  5030. }
  5031. //----------------------------------------------------------------------------
  5032. VOID
  5033. MakePartialMdl (
  5034. IN tCONNECTELE *pConnEle,
  5035. IN PIRP pIrp,
  5036. IN ULONG ToCopy
  5037. )
  5038. /*++
  5039. Routine Description:
  5040. This routine is called to build a partial Mdl that accounts for ToCopy
  5041. bytes of data being copied to the start of the Client's Mdl.
  5042. Arguments:
  5043. pConnEle - ptr to the connection element
  5044. Return Value:
  5045. NTSTATUS - Status of event indication
  5046. --*/
  5047. {
  5048. PMDL pNewMdl;
  5049. PVOID NewAddress;
  5050. // Build a partial Mdl to represent the client's Mdl chain since
  5051. // we have copied data to it, and the transport must copy
  5052. // more data to it after that data.
  5053. //
  5054. SumMdlLengths(pIrp->MdlAddress,ToCopy,pConnEle);
  5055. // this routine has set the Mdl that the next data starts at and
  5056. // the offset from the start of that Mdl, so create a partial Mdl
  5057. // to map that buffer and tack it on the mdl chain instead of the
  5058. // original
  5059. //
  5060. pNewMdl = pConnEle->pNewMdl;
  5061. NewAddress = (PVOID)((PUCHAR)MmGetMdlVirtualAddress(pConnEle->pNextMdl)
  5062. + pConnEle->OffsetFromStart);
  5063. if ((MmGetMdlByteCount(pConnEle->pNextMdl) - pConnEle->OffsetFromStart) > MAXUSHORT)
  5064. {
  5065. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,MAXUSHORT);
  5066. }
  5067. else
  5068. {
  5069. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,0);
  5070. }
  5071. // hook the new partial mdl to the front of the MDL chain
  5072. //
  5073. pNewMdl->Next = pConnEle->pNextMdl->Next;
  5074. pIrp->MdlAddress = pNewMdl;
  5075. ASSERT(pNewMdl);
  5076. }
  5077. //----------------------------------------------------------------------------
  5078. VOID
  5079. CopyToStartofIndicate (
  5080. IN tLOWERCONNECTION *pLowerConn,
  5081. IN ULONG DataTaken
  5082. )
  5083. /*++
  5084. Routine Description:
  5085. This routine is called to copy data remaining in the indicate buffer to
  5086. the head of the indicate buffer.
  5087. Arguments:
  5088. pLowerConn - ptr to the lower connection element
  5089. Return Value:
  5090. none
  5091. --*/
  5092. {
  5093. PVOID pSrc;
  5094. ULONG DataLeft;
  5095. PVOID pMdl;
  5096. DataLeft = pLowerConn->BytesInIndicate;
  5097. pMdl = (PVOID)MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
  5098. pSrc = (PVOID)( (PUCHAR)pMdl + DataTaken);
  5099. CTEMemCopy(pMdl,pSrc,DataLeft);
  5100. }
  5101. //----------------------------------------------------------------------------
  5102. ULONG FailuresSinceLastLog = 0;
  5103. NTSTATUS
  5104. OutOfRsrcKill(
  5105. OUT tLOWERCONNECTION *pLowerConn)
  5106. /*++
  5107. Routine Description:
  5108. This Routine handles killing a connection when an out of resource condition
  5109. occurs. It uses a special Irp that it has saved away, and a linked list
  5110. if that irp is currently in use.
  5111. Arguments:
  5112. Return Value:
  5113. NTSTATUS - status of the request
  5114. --*/
  5115. {
  5116. NTSTATUS status;
  5117. CTELockHandle OldIrq;
  5118. CTELockHandle OldIrq1;
  5119. PIRP pIrp;
  5120. PFILE_OBJECT pFileObject;
  5121. PDEVICE_OBJECT pDeviceObject;
  5122. tDEVICECONTEXT *pDeviceContext = pLowerConn->pDeviceContext;
  5123. CTESystemTime CurrentTime;
  5124. CTESpinLock(pDeviceContext,OldIrq);
  5125. CTESpinLock(&NbtConfig,OldIrq1);
  5126. //
  5127. // TCP could fail a TDI_RECEIVE requests upon a disconnection.
  5128. // Don't go through the OutOfRsrcKill logic in this case.
  5129. //
  5130. if (pLowerConn->bNoOutRsrcKill) {
  5131. CTESpinFree(&NbtConfig,OldIrq1);
  5132. CTESpinFree(pDeviceContext,OldIrq);
  5133. return STATUS_SUCCESS;
  5134. }
  5135. //
  5136. // If we have not logged any event recently, then log an event!
  5137. //
  5138. CTEQuerySystemTime (CurrentTime);
  5139. FailuresSinceLastLog++;
  5140. if (pLowerConn->pUpperConnection && // Log it only when the connection hasn't been disconnected
  5141. (CurrentTime.QuadPart-NbtConfig.LastOutOfRsrcLogTime.QuadPart) > ((ULONGLONG) ONE_HOUR*10000))
  5142. {
  5143. NbtLogEvent (EVENT_NBT_NO_RESOURCES, FailuresSinceLastLog, 0x117);
  5144. NbtConfig.LastOutOfRsrcLogTime = CurrentTime;
  5145. FailuresSinceLastLog = 0;
  5146. }
  5147. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_OUT_OF_RSRC);
  5148. if (NbtConfig.OutOfRsrc.pIrp)
  5149. {
  5150. // get an Irp to send the message in
  5151. pIrp = NbtConfig.OutOfRsrc.pIrp;
  5152. NbtConfig.OutOfRsrc.pIrp = NULL;
  5153. pFileObject = pLowerConn->pFileObject;
  5154. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  5155. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  5156. CTESpinFree(&NbtConfig,OldIrq1);
  5157. CTESpinFree(pDeviceContext,OldIrq);
  5158. // store some context stuff in the Irp stack so we can call the completion
  5159. // routine set by the Udpsend code...
  5160. TdiBuildDisconnect(
  5161. pIrp,
  5162. pDeviceObject,
  5163. pFileObject,
  5164. RsrcKillCompletion,
  5165. pLowerConn, //context value passed to completion routine
  5166. NULL, // Timeout...
  5167. TDI_DISCONNECT_ABORT,
  5168. NULL, // send connection info
  5169. NULL); // return connection info
  5170. CHECK_PTR(pIrp);
  5171. pIrp->MdlAddress = NULL;
  5172. CHECK_COMPLETION(pIrp);
  5173. status = IoCallDriver(pDeviceObject,pIrp);
  5174. IF_DBG(NBT_DEBUG_REF)
  5175. KdPrint(("Nbt.OutOfRsrcKill: Kill connection, %X\n",pLowerConn));
  5176. return(status);
  5177. }
  5178. else
  5179. {
  5180. //
  5181. // The lower conn could get removed here, then get dequed from the ConnectionHead and come here
  5182. // (via DpcNextOutOfRsrcKill), and fail to get an Irp; we re-enque it into the OutOfRsrc list,
  5183. // but should not try to deque it here.
  5184. //
  5185. if (!pLowerConn->OutOfRsrcFlag)
  5186. {
  5187. RemoveEntryList(&pLowerConn->Linkage);
  5188. //
  5189. // The lower conn gets removed from the inactive list here and again when
  5190. // DelayedCleanupAfterDisconnect calls NbtDeleteLowerConn. In order to prevent
  5191. // the second deque, we set a flag here and test for it in NbtDeleteLowerConn.
  5192. //
  5193. pLowerConn->OutOfRsrcFlag = TRUE;
  5194. }
  5195. pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (PLIST_ENTRY)0x00006041;
  5196. InsertTailList(&NbtConfig.OutOfRsrc.ConnectionHead,&pLowerConn->Linkage);
  5197. CTESpinFree(&NbtConfig,OldIrq1);
  5198. CTESpinFree(pDeviceContext,OldIrq);
  5199. }
  5200. return(STATUS_SUCCESS);
  5201. }
  5202. //----------------------------------------------------------------------------
  5203. NTSTATUS
  5204. RsrcKillCompletion(
  5205. IN PDEVICE_OBJECT DeviceObject,
  5206. IN PIRP pIrp,
  5207. IN PVOID pContext
  5208. )
  5209. /*++
  5210. Routine Description:
  5211. This routine handles the completion of a disconnect to the transport.
  5212. Arguments:
  5213. Return Value:
  5214. NTSTATUS - success or not
  5215. --*/
  5216. {
  5217. NTSTATUS status;
  5218. KIRQL OldIrq;
  5219. PLIST_ENTRY pEntry;
  5220. tLOWERCONNECTION *pLowerConn;
  5221. PKDPC pDpc;
  5222. pLowerConn = (tLOWERCONNECTION *)pContext;
  5223. // this call will indicate the disconnect to the client and clean up
  5224. // abit.
  5225. //
  5226. status = DisconnectHndlrNotOs (NULL,
  5227. (PVOID)pLowerConn,
  5228. 0,
  5229. NULL,
  5230. 0,
  5231. NULL,
  5232. TDI_DISCONNECT_ABORT);
  5233. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_OUT_OF_RSRC, FALSE);
  5234. CTESpinLock(&NbtConfig,OldIrq);
  5235. NbtConfig.OutOfRsrc.pIrp = pIrp;
  5236. if (!IsListEmpty(&NbtConfig.OutOfRsrc.ConnectionHead))
  5237. {
  5238. if (NbtConfig.OutOfRsrc.pDpc)
  5239. {
  5240. pDpc = NbtConfig.OutOfRsrc.pDpc;
  5241. NbtConfig.OutOfRsrc.pDpc = NULL;
  5242. pEntry = RemoveHeadList(&NbtConfig.OutOfRsrc.ConnectionHead);
  5243. pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
  5244. pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (PLIST_ENTRY)0x00006109;
  5245. KeInitializeDpc(pDpc, DpcNextOutOfRsrcKill, (PVOID)pLowerConn);
  5246. KeInsertQueueDpc(pDpc,NULL,NULL);
  5247. CTESpinFree(&NbtConfig,OldIrq);
  5248. }
  5249. else
  5250. {
  5251. CTESpinFree(&NbtConfig,OldIrq);
  5252. }
  5253. }
  5254. else
  5255. {
  5256. CTESpinFree(&NbtConfig,OldIrq);
  5257. }
  5258. //
  5259. // return this status to stop the IO subsystem from further processing the
  5260. // IRP - i.e. trying to complete it back to the initiating thread! -since
  5261. // there is no initiating thread - we are the initiator
  5262. //
  5263. return(STATUS_MORE_PROCESSING_REQUIRED);
  5264. }
  5265. //----------------------------------------------------------------------------
  5266. VOID
  5267. DpcNextOutOfRsrcKill(
  5268. IN PKDPC pDpc,
  5269. IN PVOID Context,
  5270. IN PVOID SystemArgument1,
  5271. IN PVOID SystemArgument2
  5272. )
  5273. /*++
  5274. Routine Description:
  5275. This routine simply calls OutOfRsrcKill from a Dpc started in
  5276. RsrcKillCompletion.
  5277. Arguments:
  5278. Return Value:
  5279. --*/
  5280. {
  5281. KIRQL OldIrq;
  5282. tLOWERCONNECTION *pLowerConn;
  5283. pLowerConn = (tLOWERCONNECTION *)Context;
  5284. CTESpinLock(&NbtConfig,OldIrq);
  5285. NbtConfig.OutOfRsrc.pDpc = pDpc;
  5286. CTESpinFree(&NbtConfig,OldIrq);
  5287. OutOfRsrcKill(pLowerConn);
  5288. //
  5289. // to remove the extra reference put on pLowerConn when OutOfRsrc called
  5290. //
  5291. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_OUT_OF_RSRC, FALSE);
  5292. }
  5293. //----------------------------------------------------------------------------
  5294. VOID
  5295. NbtCancelFillIrpRoutine(
  5296. IN PDEVICE_OBJECT DeviceContext,
  5297. IN PIRP pIrp
  5298. )
  5299. /*++
  5300. Routine Description:
  5301. This routine handles the cancelling a Receive Irp that has been saved
  5302. during the FILL_IRP state. It must release the
  5303. cancel spin lock before returning re: IoCancelIrp().
  5304. Arguments:
  5305. Return Value:
  5306. The final status from the operation.
  5307. --*/
  5308. {
  5309. tCONNECTELE *pConnEle;
  5310. KIRQL OldIrq;
  5311. KIRQL OldIrq1;
  5312. KIRQL OldIrq2;
  5313. PIO_STACK_LOCATION pIrpSp;
  5314. tLOWERCONNECTION *pLowerConn;
  5315. BOOLEAN CompleteIt = FALSE;
  5316. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  5317. KdPrint(("Nbt.NbtCancelFillIrpRoutine: Got a Receive Cancel Irp !!! *****************\n"));
  5318. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  5319. pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
  5320. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  5321. if (!NBT_VERIFY_HANDLE2 (pConnEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
  5322. {
  5323. ASSERTMSG ("Nbt.NbtCancelFillIrpRoutine: ERROR - Invalid Connection Handle\n", 0);
  5324. // complete the irp
  5325. pIrp->IoStatus.Status = STATUS_INVALID_HANDLE;
  5326. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  5327. return;
  5328. }
  5329. // now look for an Irp to cancel
  5330. //
  5331. CHECK_PTR(pConnEle);
  5332. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  5333. CTESpinLock(pConnEle,OldIrq);
  5334. pLowerConn = pConnEle->pLowerConnId;
  5335. if (pLowerConn)
  5336. {
  5337. CTESpinLock(pLowerConn,OldIrq2);
  5338. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, RejectAnyData);
  5339. }
  5340. pConnEle->pIrpRcv = NULL;
  5341. if (pLowerConn)
  5342. {
  5343. CTESpinFree(pLowerConn,OldIrq2);
  5344. }
  5345. CTESpinFree(pConnEle,OldIrq);
  5346. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  5347. // complete the irp
  5348. pIrp->IoStatus.Status = STATUS_CANCELLED;
  5349. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  5350. if (pLowerConn)
  5351. {
  5352. //
  5353. // Cancelling a Rcv Irp in the fill irp state will cause netbt
  5354. // to lose track of where it is in the message so it must kill
  5355. // the connection.
  5356. //
  5357. OutOfRsrcKill(pLowerConn);
  5358. }
  5359. return;
  5360. }