Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6529 lines
210 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 tCONNECTELE *pConnEle,
  172. IN CTELockHandle OldIrq
  173. );
  174. NTSTATUS
  175. CopyDataandIndicate(
  176. IN PVOID ReceiveEventContext,
  177. IN PVOID ConnectionContext,
  178. IN USHORT ReceiveFlags,
  179. IN ULONG BytesIndicated,
  180. IN ULONG BytesAvailable,
  181. OUT PULONG BytesTaken,
  182. IN PVOID pTsdu,
  183. OUT PIRP *ppIrp
  184. );
  185. VOID
  186. SumMdlLengths (
  187. IN PMDL pMdl,
  188. IN ULONG BytesAvailable,
  189. IN tCONNECTELE *pConnectEle
  190. );
  191. NTSTATUS
  192. RsrcKillCompletion(
  193. IN PDEVICE_OBJECT DeviceObject,
  194. IN PIRP pIrp,
  195. IN PVOID pContext
  196. );
  197. VOID
  198. NbtCancelFillIrpRoutine(
  199. IN PDEVICE_OBJECT DeviceContext,
  200. IN PIRP pIrp
  201. );
  202. NTSTATUS
  203. NameSrvCompletionRoutine(
  204. IN PDEVICE_OBJECT DeviceObject,
  205. IN PIRP Irp,
  206. IN PVOID Context
  207. );
  208. #ifdef _NETBIOSLESS
  209. NTSTATUS
  210. PerformInboundProcessing(
  211. tDEVICECONTEXT *pDeviceContext,
  212. tLOWERCONNECTION *pLowerConn,
  213. PTA_IP_ADDRESS pIpAddress
  214. );
  215. #endif
  216. //----------------------------------------------------------------------------
  217. __inline
  218. NTSTATUS
  219. Normal(
  220. IN PVOID ReceiveEventContext,
  221. IN tLOWERCONNECTION *pLowerConn,
  222. IN USHORT ReceiveFlags,
  223. IN ULONG BytesIndicated,
  224. IN ULONG BytesAvailable,
  225. OUT PULONG BytesTaken,
  226. IN PVOID pTsdu,
  227. OUT PVOID *ppIrp
  228. )
  229. /*++
  230. Routine Description:
  231. This routine is the receive event indication handler.
  232. It is called when an session packet arrives from the network. It calls
  233. a non OS specific routine to decide what to do. That routine passes back
  234. either a RcvElement (buffer) or a client rcv handler to call.
  235. Arguments:
  236. Return Value:
  237. NTSTATUS - Status of receive operation
  238. --*/
  239. {
  240. ASSERTMSG("Should not execute this procedure",0);
  241. return(STATUS_SUCCESS);
  242. }
  243. //----------------------------------------------------------------------------
  244. NTSTATUS
  245. LessThan4BytesRcvd(
  246. IN tLOWERCONNECTION *pLowerConn,
  247. IN ULONG BytesAvailable,
  248. OUT PULONG BytesTaken,
  249. OUT PVOID *ppIrp
  250. )
  251. /*++
  252. Routine Description:
  253. This routine handles the case when data has arrived on a connection but
  254. there isn't 128 bytes yet or a whole pdu.
  255. Arguments:
  256. Return Value:
  257. NTSTATUS - Status of receive operation
  258. --*/
  259. {
  260. tCONNECTELE *pConnectEle;
  261. NTSTATUS status;
  262. // for short indications less than 4 bytes we can't determine
  263. // the pdu size so just get the header first then get the
  264. // whole pdu next.
  265. status = NtBuildIrpForReceive(pLowerConn,
  266. sizeof(tSESSIONHDR),
  267. (PVOID *)ppIrp);
  268. pConnectEle = pLowerConn->pUpperConnection;
  269. pConnectEle->BytesInXport = BytesAvailable;
  270. if (!NT_SUCCESS(status))
  271. {
  272. CTESpinFreeAtDpc(pLowerConn);
  273. OutOfRsrcKill(pLowerConn);
  274. CTESpinLockAtDpc(pLowerConn);
  275. return( STATUS_DATA_NOT_ACCEPTED);
  276. }
  277. //
  278. // set the irp mdl length to size of session hdr so that
  279. // we don't get more than one session pdu into the buffer
  280. //
  281. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  282. *BytesTaken = 0;
  283. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  284. KdPrint(("Nbt:Switching to Ind Buff(<4 bytes), Avail = %X\n",
  285. BytesAvailable));
  286. PUSH_LOCATION(0);
  287. return(STATUS_MORE_PROCESSING_REQUIRED);
  288. }
  289. //----------------------------------------------------------------------------
  290. NTSTATUS
  291. ClientTookSomeOfTheData(
  292. IN tLOWERCONNECTION *pLowerConn,
  293. IN ULONG BytesIndicated,
  294. IN ULONG BytesAvailable,
  295. IN ULONG BytesTaken,
  296. IN ULONG PduSize
  297. )
  298. /*++
  299. Routine Description:
  300. This routine handles the case when data has arrived on a connection but
  301. the client has not taken all of the data indicated to it.
  302. Arguments:
  303. Return Value:
  304. NTSTATUS - Status of receive operation
  305. --*/
  306. {
  307. tCONNECTELE *pConnectEle;
  308. //
  309. // took some of the data, so keep track of the
  310. // rest of the data left here by going to the PARTIALRCV
  311. // state.
  312. //
  313. PUSH_LOCATION(0x5);
  314. SET_STATERCV_LOWER(pLowerConn, PARTIAL_RCV, PartialRcv);
  315. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  316. KdPrint(("Nbt.ClientTookSomeOfTheData: Switch to Partial Rcv Indicated=%X, PduSize=%X\n",
  317. BytesIndicated,PduSize-4));
  318. // Note: PduSize must include the 4 byte session header for this to
  319. // work correctly.
  320. //
  321. pConnectEle = pLowerConn->pUpperConnection;
  322. //
  323. // We always indicate the whole Pdu size to the client, so the amount
  324. // indicated is that minus what was taken - typically the 4 byte
  325. // session hdr
  326. //
  327. pConnectEle->ReceiveIndicated = PduSize - BytesTaken;
  328. // amount left in the transport...
  329. pConnectEle->BytesInXport = BytesAvailable - BytesTaken;
  330. // need to return this status since we took the 4 bytes
  331. // session header at least, even if the client took none.
  332. return(STATUS_SUCCESS);
  333. }
  334. //----------------------------------------------------------------------------
  335. NTSTATUS
  336. MoreDataRcvdThanNeeded(
  337. IN tLOWERCONNECTION *pLowerConn,
  338. IN ULONG BytesIndicated,
  339. IN ULONG BytesAvailable,
  340. OUT PULONG BytesTaken,
  341. IN PVOID pTsdu,
  342. OUT PVOID *ppIrp
  343. )
  344. /*++
  345. Routine Description:
  346. This routine handles the case when data has arrived on a connection but
  347. there isn't 128 bytes yet or a whole pdu.
  348. Arguments:
  349. Return Value:
  350. NTSTATUS - Status of receive operation
  351. --*/
  352. {
  353. tCONNECTELE *pConnectEle;
  354. ULONG Length;
  355. ULONG Remaining;
  356. ULONG PduSize;
  357. NTSTATUS status;
  358. tSESSIONHDR UNALIGNED *pSessionHdr;
  359. PUSH_LOCATION(0x6);
  360. //
  361. // there is too much data, so keep track of the
  362. // fact that there is data left in the transport
  363. // and get it with the indicate buffer
  364. //
  365. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  366. ASSERT(pLowerConn->BytesInIndicate == 0);
  367. #if DBG
  368. if (pLowerConn->BytesInIndicate)
  369. {
  370. KdPrint(("Nbt:Bytes in indicate should be ZERO, but are = %X\n",
  371. pLowerConn->BytesInIndicate));
  372. }
  373. #endif
  374. pConnectEle = pLowerConn->pUpperConnection;
  375. pConnectEle->BytesInXport = BytesAvailable - *BytesTaken;
  376. //
  377. // for short indications less than 4 bytes we can't determine
  378. // the pdu size so just get the header first then get the
  379. // whole pdu next.
  380. //
  381. Remaining = BytesIndicated - *BytesTaken;
  382. if ((LONG) Remaining < (LONG) sizeof(tSESSIONHDR))
  383. {
  384. status = NtBuildIrpForReceive(pLowerConn,sizeof(tSESSIONHDR),(PVOID *)ppIrp);
  385. if (!NT_SUCCESS(status))
  386. {
  387. // this is a serious error - we must
  388. // kill of the connection and let the
  389. // redirector restart it
  390. KdPrint(("Nbt:Unable to get an Irp for RCv - Closing Connection!! %X\n",pLowerConn));
  391. CTESpinFreeAtDpc(pLowerConn);
  392. OutOfRsrcKill(pLowerConn);
  393. CTESpinLockAtDpc(pLowerConn);
  394. return(STATUS_DATA_NOT_ACCEPTED);
  395. }
  396. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  397. KdPrint(("Nbt:< 4 Bytes,BytesTaken=%X,Avail=%X,Ind=%X,Remain=%X\n",
  398. *BytesTaken,BytesAvailable,BytesIndicated,
  399. Remaining));
  400. // DEBUG
  401. CTEZeroMemory(MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl),
  402. NBT_INDICATE_BUFFER_SIZE);
  403. PUSH_LOCATION(0x7);
  404. status = STATUS_MORE_PROCESSING_REQUIRED;
  405. }
  406. else
  407. {
  408. // if we get to here there are enough bytes left to determine
  409. // the next pdu size...so we can determine how much
  410. // data to get for the indicate buffer
  411. //
  412. pSessionHdr = (tSESSIONHDR UNALIGNED *)((PUCHAR)pTsdu + *BytesTaken);
  413. PduSize = myntohl(pSessionHdr->UlongLength) + sizeof(tSESSIONHDR);
  414. Length = (PduSize > NBT_INDICATE_BUFFER_SIZE) ?
  415. NBT_INDICATE_BUFFER_SIZE : PduSize;
  416. //
  417. // The NewSessionCompletion routine recalculates
  418. // what is left in the transport when the
  419. // irp completes
  420. //
  421. status = NtBuildIrpForReceive(pLowerConn,Length,(PVOID *)ppIrp);
  422. if (!NT_SUCCESS(status))
  423. {
  424. // this is a serious error - we must
  425. // kill of the connection and let the
  426. // redirector restart it
  427. KdPrint(("Nbt:Unable to get an Irp for RCV(2) - Closing Connection!! %X\n",pLowerConn));
  428. CTESpinFreeAtDpc(pLowerConn);
  429. OutOfRsrcKill(pLowerConn);
  430. CTESpinLockAtDpc(pLowerConn);
  431. return(STATUS_DATA_NOT_ACCEPTED);
  432. }
  433. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  434. KdPrint(("Nbt:Switch to Ind Buff, InXport = %X, Pdusize=%X,ToGet=%X\n",
  435. pConnectEle->BytesInXport,PduSize-4,Length));
  436. }
  437. return(STATUS_MORE_PROCESSING_REQUIRED);
  438. }
  439. //----------------------------------------------------------------------------
  440. NTSTATUS
  441. NotEnoughDataYet(
  442. IN tLOWERCONNECTION *pLowerConn,
  443. IN ULONG BytesIndicated,
  444. IN ULONG BytesAvailable,
  445. OUT PULONG BytesTaken,
  446. IN ULONG PduSize,
  447. OUT PVOID *ppIrp
  448. )
  449. /*++
  450. Routine Description:
  451. This routine handles the case when data has arrived on a connection but
  452. there isn't 128 bytes yet or a whole pdu.
  453. Arguments:
  454. Return Value:
  455. NTSTATUS - Status of receive operation
  456. --*/
  457. {
  458. NTSTATUS status;
  459. tCONNECTELE *pConnectEle;
  460. ULONG Length;
  461. PUSH_LOCATION(0x9);
  462. //
  463. // not enough data indicated, so use the indicate buffer
  464. //
  465. Length = (PduSize > NBT_INDICATE_BUFFER_SIZE) ?
  466. NBT_INDICATE_BUFFER_SIZE : PduSize;
  467. status = NtBuildIrpForReceive(pLowerConn,Length,(PVOID *)ppIrp);
  468. if (!NT_SUCCESS(status))
  469. {
  470. CTESpinFreeAtDpc(pLowerConn);
  471. OutOfRsrcKill(pLowerConn);
  472. CTESpinLockAtDpc(pLowerConn);
  473. return(STATUS_DATA_NOT_ACCEPTED);
  474. }
  475. *BytesTaken = 0;
  476. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  477. pConnectEle = pLowerConn->pUpperConnection;
  478. pConnectEle->BytesInXport = BytesAvailable;
  479. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  480. KdPrint(("Nbt:Not Enough data indicated in Tdihndlr, using indic. buffer Indicated = %X,Avail=%X,PduSize= %X\n",
  481. BytesIndicated, BytesAvailable,PduSize-4));
  482. return(STATUS_MORE_PROCESSING_REQUIRED);
  483. }
  484. //----------------------------------------------------------------------------
  485. NTSTATUS
  486. FillIrp(
  487. IN PVOID ReceiveEventContext,
  488. IN tLOWERCONNECTION *pLowerConn,
  489. IN USHORT ReceiveFlags,
  490. IN ULONG BytesIndicated,
  491. IN ULONG BytesAvailable,
  492. OUT PULONG BytesTaken,
  493. IN PVOID pTsdu,
  494. OUT PVOID *ppIrp
  495. )
  496. /*++
  497. Routine Description:
  498. This routine is the receive event indication handler.
  499. It is called when an session packet arrives from the network. It calls
  500. a non OS specific routine to decide what to do. That routine passes back
  501. either a RcvElement (buffer) or a client rcv handler to call.
  502. Arguments:
  503. Return Value:
  504. NTSTATUS - Status of receive operation
  505. --*/
  506. {
  507. ASSERTMSG("Should not execute this procedure",0);
  508. return(STATUS_SUCCESS);
  509. // do nothing
  510. }
  511. //----------------------------------------------------------------------------
  512. NTSTATUS
  513. IndicateBuffer(
  514. IN PVOID ReceiveEventContext,
  515. IN tLOWERCONNECTION *pLowerConn,
  516. IN USHORT ReceiveFlags,
  517. IN ULONG BytesIndicated,
  518. IN ULONG BytesAvailable,
  519. OUT PULONG BytesTaken,
  520. IN PVOID pTsdu,
  521. OUT PVOID *ppIrp
  522. )
  523. /*++
  524. Routine Description:
  525. This routine handles reception of data while in the IndicateBuffer state.
  526. In this state the indicate buffer is receiveing data until at least
  527. 128 bytes have been receive, or a whole pdu has been received.
  528. Arguments:
  529. Return Value:
  530. NTSTATUS - Status of receive operation
  531. --*/
  532. {
  533. tCONNECTELE *pConnectEle;
  534. NTSTATUS status;
  535. ULONG PduSize;
  536. ULONG ToCopy;
  537. PVOID pIndicateBuffer;
  538. ULONG Taken;
  539. //
  540. // there is data in the indicate buffer and we got a new
  541. // indication, so copy some or all of the indication to the
  542. // indicate buffer
  543. //
  544. PVOID pDest;
  545. ULONG RemainPdu;
  546. ULONG SpaceLeft;
  547. ULONG TotalBytes;
  548. ULONG ToCopy1=0;
  549. INCR_COUNT(R3);
  550. PUSH_LOCATION(0xe);
  551. pConnectEle = pLowerConn->pUpperConnection;
  552. ASSERT(pLowerConn->StateRcv == INDICATE_BUFFER);
  553. //
  554. // The indicate buffer always starts with a pdu
  555. //
  556. pIndicateBuffer = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
  557. // the location to start copying the new data into is right
  558. // after the existing data in the buffer
  559. //
  560. pDest = (PVOID)((PUCHAR)pIndicateBuffer + pLowerConn->BytesInIndicate);
  561. //
  562. // the session header may not be all into the indicate
  563. // buffer yet, so check that before getting the pdu length.
  564. //
  565. if (pLowerConn->BytesInIndicate < sizeof(tSESSIONHDR))
  566. {
  567. PUSH_LOCATION(0xe);
  568. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  569. KdPrint(("Nbt:Too Few in Indicate Buff, Adding InIndicate %X\n",
  570. pLowerConn->BytesInIndicate));
  571. ToCopy1 = sizeof(tSESSIONHDR) - pLowerConn->BytesInIndicate;
  572. if (ToCopy1 > BytesIndicated)
  573. {
  574. ToCopy1 = BytesIndicated;
  575. }
  576. CTEMemCopy(pDest,pTsdu,ToCopy1);
  577. pDest = (PVOID)((PUCHAR)pDest + ToCopy1);
  578. pTsdu = (PVOID)((PUCHAR)pTsdu + ToCopy1);
  579. pLowerConn->BytesInIndicate += (USHORT)ToCopy1;
  580. *BytesTaken = ToCopy1;
  581. }
  582. // now check again, and pass down an irp to get more data if necessary
  583. //
  584. if (pLowerConn->BytesInIndicate < sizeof(tSESSIONHDR))
  585. {
  586. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  587. KdPrint(("Nbt:< 4 Bytes in IndicBuff, BytesinInd= %X, BytesIndicated=%x\n",
  588. pLowerConn->BytesInIndicate,BytesIndicated));
  589. PUSH_LOCATION(0xF);
  590. //
  591. // the data left in the transport is what was Available
  592. // minus what we just copied to the indicate buffer
  593. //
  594. pConnectEle->BytesInXport = BytesAvailable - ToCopy1;
  595. if (pConnectEle->BytesInXport)
  596. {
  597. PUSH_LOCATION(0x10);
  598. //
  599. // pass the indicate buffer down to get some more data
  600. // to fill out to the end of the session hdr
  601. //
  602. NtBuildIndicateForReceive(pLowerConn,
  603. sizeof(tSESSIONHDR)-pLowerConn->BytesInIndicate,
  604. (PVOID *)ppIrp);
  605. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  606. KdPrint(("Nbt:INDIC_BUF...need more data for hdr Avail= %X, InXport = %X\n",
  607. BytesAvailable,pConnectEle->BytesInXport,pLowerConn));
  608. return(STATUS_MORE_PROCESSING_REQUIRED);
  609. }
  610. // if we get to here there isn't 4 bytes in the indicate buffer and
  611. // there is no more data in the Transport, so just wait for the next
  612. // indication.
  613. //
  614. return(STATUS_SUCCESS);
  615. }
  616. PduSize = myntohl(((tSESSIONHDR *)pIndicateBuffer)->UlongLength)
  617. + sizeof(tSESSIONHDR);
  618. // copy up to 132 bytes or the whole pdu to the indicate buffer
  619. //
  620. RemainPdu = PduSize - pLowerConn->BytesInIndicate;
  621. SpaceLeft = NBT_INDICATE_BUFFER_SIZE - pLowerConn->BytesInIndicate;
  622. if (RemainPdu < SpaceLeft)
  623. ToCopy = RemainPdu;
  624. else
  625. ToCopy = SpaceLeft;
  626. if (ToCopy > (BytesIndicated-ToCopy1))
  627. {
  628. ToCopy = (BytesIndicated - ToCopy1);
  629. }
  630. //
  631. // Copy the indication or part of it to the indication
  632. // buffer
  633. //
  634. CTEMemCopy(pDest,pTsdu,ToCopy);
  635. pLowerConn->BytesInIndicate += (USHORT)ToCopy;
  636. TotalBytes = pLowerConn->BytesInIndicate;
  637. // the amount of data taken is the amount copied to the
  638. // indicate buffer
  639. //
  640. *BytesTaken = ToCopy + ToCopy1;
  641. #if DBG
  642. {
  643. tSESSIONHDR UNALIGNED *pSessionHdr;
  644. pSessionHdr = (tSESSIONHDR UNALIGNED *)pIndicateBuffer;
  645. ASSERT((pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE) ||
  646. (pSessionHdr->Type == NBT_SESSION_MESSAGE));
  647. }
  648. #endif
  649. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  650. KdPrint(("Nbt:INDIC_BUFF, TotalBytes= %X, InIndic=%X, Copied(0/1)= %X %X Avail %X\n",
  651. TotalBytes,pLowerConn->BytesInIndicate,ToCopy,ToCopy1,BytesAvailable));
  652. // the data left in the transport is what was Available
  653. // minus what we just copied to the indicate buffer
  654. //
  655. pConnectEle->BytesInXport = BytesAvailable - *BytesTaken;
  656. // now check if we have a whole pdu or 132 bytes, either way
  657. // enough to indicate to the client.
  658. //
  659. ASSERT(TotalBytes <= NBT_INDICATE_BUFFER_SIZE);
  660. if ((TotalBytes < NBT_INDICATE_BUFFER_SIZE) && (TotalBytes < PduSize) && (pConnectEle->BytesInXport)) {
  661. //
  662. // This could happen if BytesIndicated < BytesAvailable
  663. //
  664. ToCopy = PduSize;
  665. if (ToCopy > NBT_INDICATE_BUFFER_SIZE) {
  666. ToCopy = NBT_INDICATE_BUFFER_SIZE;
  667. }
  668. ASSERT (TotalBytes == pLowerConn->BytesInIndicate);
  669. NtBuildIndicateForReceive(pLowerConn, ToCopy - TotalBytes, (PVOID *)ppIrp);
  670. #if DBG
  671. HitCounter++;
  672. #endif
  673. return(STATUS_MORE_PROCESSING_REQUIRED);
  674. }
  675. if ((TotalBytes == NBT_INDICATE_BUFFER_SIZE) ||
  676. (TotalBytes == PduSize))
  677. {
  678. status = CopyDataandIndicate(
  679. ReceiveEventContext,
  680. (PVOID)pLowerConn,
  681. ReceiveFlags,
  682. TotalBytes,
  683. pConnectEle->BytesInXport + TotalBytes,
  684. &Taken,
  685. pIndicateBuffer,
  686. (PIRP *)ppIrp);
  687. }
  688. else
  689. {
  690. // not enough data in the indicate buffer yet
  691. // NOTE: *BytesTaken should be set correctly above...
  692. // = ToCopy + ToCopy1;
  693. PUSH_LOCATION(0x11);
  694. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  695. KdPrint(("Nbt:Not Enough data indicated(INDICBUFF state), Indicated = %X,PduSize= %X,InIndic=%X\n",
  696. BytesIndicated, PduSize, pLowerConn->BytesInIndicate));
  697. status = STATUS_SUCCESS;
  698. }
  699. return(status);
  700. }
  701. //----------------------------------------------------------------------------
  702. NTSTATUS
  703. PartialRcv(
  704. IN PVOID ReceiveEventContext,
  705. IN tLOWERCONNECTION *pLowerConn,
  706. IN USHORT ReceiveFlags,
  707. IN ULONG BytesIndicated,
  708. IN ULONG BytesAvailable,
  709. OUT PULONG BytesTaken,
  710. IN PVOID pTsdu,
  711. OUT PVOID *ppIrp
  712. )
  713. /*++
  714. Routine Description:
  715. This routine is the receive event indication handler.
  716. It is called when an session packet arrives from the network. It calls
  717. a non OS specific routine to decide what to do. That routine passes back
  718. either a RcvElement (buffer) or a client rcv handler to call.
  719. Arguments:
  720. Return Value:
  721. NTSTATUS - Status of receive operation
  722. --*/
  723. {
  724. tCONNECTELE *pConnectEle;
  725. //
  726. // the data for the client may be in the indicate buffer and
  727. // in this case the transport could indicate us with more data. Therefore
  728. // track the number of bytes available in the transport which
  729. // we will get when the client finally posts a buffer.
  730. // This state could also happen on a zero length Rcv when the
  731. // client does not accept the data, and later posts a rcv
  732. // buffer for the zero length rcv.
  733. //
  734. INCR_COUNT(R4);
  735. PUSH_LOCATION(0x13);
  736. ASSERT(pLowerConn->StateRcv == PARTIAL_RCV);
  737. pConnectEle = pLowerConn->pUpperConnection;
  738. // ASSERT(pConnectEle->BytesInXport == 0);
  739. #if DBG
  740. if (pConnectEle->BytesInXport != 0)
  741. {
  742. KdPrint(("Nbt.PartialRcv: pConnectEle->BytesInXport != 0 Avail %X, InIndicate=%X,InXport %X %X\n",
  743. BytesAvailable,pLowerConn->BytesInIndicate,
  744. pConnectEle->BytesInXport,pLowerConn));
  745. }
  746. #endif // DBG
  747. pConnectEle->BytesInXport = BytesAvailable;
  748. IF_DBG(NBT_DEBUG_NAMESRV)
  749. KdPrint(("Nbt:Got Indicated while in PartialRcv state Avail %X, InIndicate=%X,InXport %X %X\n",
  750. BytesAvailable,pLowerConn->BytesInIndicate,
  751. pConnectEle->BytesInXport,pLowerConn));
  752. *BytesTaken = 0;
  753. return(STATUS_SUCCESS);
  754. }
  755. //----------------------------------------------------------------------------
  756. NTSTATUS
  757. TdiReceiveHandler (
  758. IN PVOID ReceiveEventContext,
  759. IN PVOID ConnectionContext,
  760. IN USHORT ReceiveFlags,
  761. IN ULONG BytesIndicated,
  762. IN ULONG BytesAvailable,
  763. OUT PULONG BytesTaken,
  764. IN PVOID pTsdu,
  765. OUT PIRP *ppIrp
  766. )
  767. /*++
  768. Routine Description:
  769. This routine is the receive event indication handler.
  770. It is called when an session packet arrives from the network. It calls
  771. a non OS specific routine to decide what to do. That routine passes back
  772. either a RcvElement (buffer) or a client rcv handler to call.
  773. Arguments:
  774. IN PVOID ReceiveEventContext - Context provided for this event when event set
  775. IN PVOID ConnectionContext - Connection Context, (pLowerConnection)
  776. IN USHORT ReceiveFlags - Flags describing the message
  777. IN ULONG BytesIndicated - Number of bytes available at indication time
  778. IN ULONG BytesAvailable - Number of bytes available to receive
  779. OUT PULONG BytesTaken - Number of bytes consumed by redirector.
  780. IN PVOID pTsdu - Data from remote machine.
  781. OUT PIRP *ppIrp - I/O request packet filled in if received data
  782. Return Value:
  783. NTSTATUS - Status of receive operation
  784. --*/
  785. {
  786. register tLOWERCONNECTION *pLowerConn;
  787. PIRP pIrp;
  788. CTELockHandle OldIrq;
  789. NTSTATUS status;
  790. tCONNECTELE *pConnEle;
  791. ULONG BTaken;
  792. *ppIrp = NULL;
  793. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  794. // NOTE:
  795. // Access is synchronized through the spin lock on pLowerConn for all
  796. // Session related stuff. This includes the case where the client
  797. // posts another Rcv Buffer in NTReceive. - so there is no need to get the
  798. // pConnEle Spin lock too.
  799. //
  800. CTESpinLock(pLowerConn,OldIrq);
  801. // pLowerConn->InRcvHandler = TRUE;
  802. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  803. // save this on the stack in case we need to dereference it below.
  804. pConnEle = pLowerConn->pUpperConnection;
  805. // call the correct routine depending on the state of the connection
  806. // Normal/FillIrp/PartialRcv/IndicateBuffer/Inbound/OutBound
  807. //
  808. if ((pLowerConn->State == NBT_SESSION_UP) &&
  809. (pLowerConn->StateRcv == FILL_IRP))
  810. {
  811. PIO_STACK_LOCATION pIrpSp;
  812. PMDL pNewMdl;
  813. PFILE_OBJECT pFileObject;
  814. ULONG RemainingPdu;
  815. PVOID NewAddress;
  816. PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
  817. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  818. KIRQL OldIrq2;
  819. ULONG RcvLength;
  820. PUSH_LOCATION(0xa);
  821. pIrp = pConnEle->pIrpRcv;
  822. if (!pIrp)
  823. {
  824. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  825. KdPrint (("Nbt:TdiReceiveHandler: No pIrpRcv for pConnEle=<%x>, pLowerConn=<%d>\n",
  826. pConnEle, pLowerConn));
  827. *BytesTaken = 0;
  828. DerefLowerConnFast(pLowerConn,pConnEle,OldIrq);
  829. return (STATUS_SUCCESS);
  830. }
  831. // we are still waiting for the rest of the session pdu so
  832. // do not call the RcvHandlrNotOs, since we already have the buffer
  833. // to put this data in.
  834. // too much data may have arrived... i.e. part of the next session pdu..
  835. // so check and set the receive length accordingly
  836. //
  837. RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  838. RcvLength = RemainingPdu;
  839. //
  840. // try high runner case first
  841. //
  842. if (BytesAvailable <= RemainingPdu)
  843. {
  844. PUSH_LOCATION(0xb);
  845. //
  846. // if the client buffer is too small to take all of the rest of the
  847. // data, shorten the receive length and keep track of how many
  848. // bytes are left in the transport. ReceiveIndicated should have
  849. // been set when the irp was passed down originally.
  850. //
  851. if (BytesAvailable > pConnEle->FreeBytesInMdl)
  852. {
  853. PUSH_LOCATION(0xb);
  854. RcvLength = pConnEle->FreeBytesInMdl;
  855. pConnEle->BytesInXport = BytesAvailable - RcvLength;
  856. }
  857. if (RcvLength > pConnEle->FreeBytesInMdl) {
  858. ASSERT(BytesAvailable <= pConnEle->FreeBytesInMdl);
  859. RcvLength = pConnEle->FreeBytesInMdl;
  860. pConnEle->BytesInXport = 0;
  861. }
  862. }
  863. else
  864. {
  865. //
  866. // start of session pdu in the middle of the indication
  867. //
  868. PUSH_LOCATION(0xc);
  869. //
  870. // It is possible that the client buffer is too short, so check
  871. // for that case.
  872. //
  873. if (RemainingPdu > pConnEle->FreeBytesInMdl)
  874. {
  875. RcvLength = pConnEle->FreeBytesInMdl;
  876. PUSH_LOCATION(0xd);
  877. }
  878. /* Remember how much data is left in the transport
  879. when this irp passes through the completionrcv routine
  880. it will pass the indication buffer back to the transport
  881. to get at least 4 bytes of header information so we
  882. can determine the next session pdu's size before receiving
  883. it. The trick is to avoid having more than one session
  884. pdu in the buffer at once.
  885. */
  886. pConnEle->BytesInXport = BytesAvailable - RcvLength;
  887. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  888. KdPrint(("Nbt:End of FILL_IRP, found new Pdu BytesInXport=%X\n",
  889. pConnEle->BytesInXport));
  890. }
  891. // if the transport has all of the data it says is available, then
  892. // do the copy here ( if the client buffer is large enough - checked
  893. // by !ReceiveIndicated)
  894. //
  895. if ((BytesAvailable == BytesIndicated) &&
  896. (RcvLength >= BytesIndicated) &&
  897. !pConnEle->ReceiveIndicated)
  898. {
  899. ULONG BytesCopied;
  900. ULONG TotalBytes;
  901. PUSH_LOCATION(0x70);
  902. if (RcvLength > BytesIndicated)
  903. RcvLength = BytesIndicated;
  904. status = TdiCopyBufferToMdl(
  905. pTsdu,
  906. 0,
  907. RcvLength,
  908. pConnEle->pNextMdl,
  909. pConnEle->OffsetFromStart,
  910. &BytesCopied);
  911. //
  912. // if the irp is not yet full, or the free bytes have not
  913. // been exhausted by this copy, then adjust some counts and return
  914. // quickly, otherwise call the completion rcv routine as if the
  915. // irp has completed normally from the transport -
  916. //
  917. TotalBytes = pConnEle->BytesRcvd + BytesCopied;
  918. if ((TotalBytes < pConnEle->TotalPcktLen) &&
  919. (BytesCopied < pConnEle->FreeBytesInMdl))
  920. {
  921. PMDL pMdl;
  922. //
  923. // take the short cut and do not call completion rcv since we
  924. // are still waiting for more data
  925. //
  926. PUSH_LOCATION(0x81);
  927. pConnEle->BytesRcvd += BytesCopied;
  928. pConnEle->FreeBytesInMdl -= BytesCopied;
  929. // clean up the partial mdl.
  930. //
  931. pMdl = pConnEle->pNewMdl;
  932. MmPrepareMdlForReuse(pMdl);
  933. // set where the next rcvd data will start, by setting the pNextMdl and
  934. // offset from start.
  935. //
  936. pMdl = pConnEle->pNextMdl;
  937. if ((BytesCopied + pConnEle->OffsetFromStart) < MmGetMdlByteCount(pMdl))
  938. {
  939. PUSH_LOCATION(0x82);
  940. //
  941. // All of this data will fit into the current Mdl, and
  942. // the next data will start in the same Mdl (if there is more data)
  943. //
  944. pConnEle->OffsetFromStart += BytesCopied;
  945. }
  946. else
  947. {
  948. PUSH_LOCATION(0x83)
  949. SumMdlLengths(pMdl,
  950. pConnEle->OffsetFromStart + BytesCopied,
  951. pConnEle);
  952. }
  953. *BytesTaken = BytesCopied;
  954. status = STATUS_SUCCESS;
  955. IF_DBG(NBT_DEBUG_FASTPATH)
  956. KdPrint(("I"));
  957. goto ExitRoutine;
  958. }
  959. else
  960. {
  961. IF_DBG(NBT_DEBUG_FASTPATH)
  962. KdPrint(("i"));
  963. CTESpinFree(pLowerConn,OldIrq);
  964. //
  965. // the values are set to this so that when Completion Rcv is
  966. // called it will increment the BytesRcvd by BytesCopied.
  967. //
  968. pIrp->IoStatus.Status = STATUS_SUCCESS;
  969. pIrp->IoStatus.Information = BytesCopied;
  970. //
  971. // now call the irp completion routine, shorting out the io
  972. // subsystem - to process the irp
  973. //
  974. status = CompletionRcv(NULL,pIrp,(PVOID)pLowerConn);
  975. //
  976. // complete the irp back to the client if required
  977. //
  978. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  979. {
  980. IoAcquireCancelSpinLock(&OldIrq2);
  981. IoSetCancelRoutine(pIrp,NULL);
  982. IoReleaseCancelSpinLock(OldIrq2);
  983. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  984. }
  985. }
  986. //
  987. // tell the transport we took all the data that we did take.
  988. // Since CompletionRcv has unlocked the spin lock and decremented
  989. // the refcount, return here.
  990. //
  991. *BytesTaken = BytesCopied;
  992. return(STATUS_SUCCESS);
  993. }
  994. else
  995. {
  996. //
  997. // Either BytesIndicated != BytesAvailable or the RcvBuffer
  998. // is too short, so make up an Irp with a partial Mdl and pass it
  999. // to the transport.
  1000. //
  1001. PUSH_LOCATION(0x71);
  1002. NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pConnEle->pNextMdl)
  1003. + pConnEle->OffsetFromStart);
  1004. /* create a partial MDL so that the new data is copied after the existing data
  1005. in the MDL. Use the pNextMdl field stored in the pConnEle
  1006. that was set up during the last receive.( since at that time
  1007. we knew the BytesAvailable then). Without this we would have to
  1008. traverse the list of Mdls for each receive.
  1009. 0 for length means map the rest of the buffer
  1010. */
  1011. pNewMdl = pConnEle->pNewMdl;
  1012. if ((MmGetMdlByteCount(pConnEle->pNextMdl) - pConnEle->OffsetFromStart) > MAXUSHORT)
  1013. {
  1014. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,MAXUSHORT);
  1015. }
  1016. else
  1017. {
  1018. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,0);
  1019. }
  1020. //
  1021. // hook the new partial mdl to the front of the MDL chain
  1022. //
  1023. pNewMdl->Next = pConnEle->pNextMdl->Next;
  1024. pIrp->MdlAddress = pNewMdl;
  1025. ASSERT(pNewMdl);
  1026. CHECK_PTR(pConnEle);
  1027. pConnEle->pIrpRcv = NULL;
  1028. IoAcquireCancelSpinLock(&OldIrq2);
  1029. IoSetCancelRoutine(pIrp,NULL);
  1030. IoReleaseCancelSpinLock(OldIrq2);
  1031. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1032. pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1033. /* this code is sped up somewhat by expanding the code here rather than calling
  1034. the TdiBuildReceive macro
  1035. make the next stack location the current one. Normally IoCallDriver
  1036. would do this but we are not going through IoCallDriver here, since the
  1037. Irp is just passed back with RcvIndication.
  1038. */
  1039. ASSERT(pIrp->CurrentLocation > 1);
  1040. IoSetNextIrpStackLocation(pIrp);
  1041. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1042. pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  1043. pParams->ReceiveLength = RcvLength;
  1044. pIrpSp->CompletionRoutine = CompletionRcv;
  1045. pIrpSp->Context = (PVOID)pLowerConn;
  1046. /* set flags so the completion routine is always invoked.
  1047. */
  1048. pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
  1049. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1050. pIrpSp->MinorFunction = TDI_RECEIVE;
  1051. pFileObject = pLowerConn->pFileObject;
  1052. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  1053. pIrpSp->FileObject = pFileObject;
  1054. pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pFileObject);
  1055. pParams->ReceiveFlags = pClientParams->ReceiveFlags;
  1056. /*
  1057. pass the Irp back to the transport
  1058. */
  1059. *ppIrp = (PVOID)pIrp;
  1060. *BytesTaken = 0;
  1061. status = STATUS_MORE_PROCESSING_REQUIRED;
  1062. }
  1063. }
  1064. else
  1065. if ((pLowerConn->State == NBT_SESSION_UP) &&
  1066. (pLowerConn->StateRcv == NORMAL))
  1067. {
  1068. ULONG PduSize;
  1069. UCHAR Passit;
  1070. INCR_COUNT(R1);
  1071. /*
  1072. check indication and if less than 1 pdu or 132 bytes then
  1073. copy to the indicate buffer and go to Indic_buffer state
  1074. The while loop allows us to indicate multiple Pdus to the
  1075. client in the event that several indications arrive in one
  1076. indication from the transport
  1077. NOTE:
  1078. It is possible to get an indication that occurs in the middle
  1079. of the pdu if the client took the first indication rather
  1080. than passing an irp back, and thence going to the FILL_IRP
  1081. state. So check if BytesRcvd is zero, meaning that we are
  1082. expecting a new PDU.
  1083. */
  1084. ASSERT(pConnEle->BytesInXport == 0);
  1085. ASSERT(pLowerConn->StateRcv == NORMAL);
  1086. if (pConnEle->BytesRcvd == 0)
  1087. {
  1088. if (BytesIndicated >= sizeof(tSESSIONHDR))
  1089. {
  1090. PduSize = myntohl(((tSESSIONHDR UNALIGNED *)pTsdu)->UlongLength)
  1091. + sizeof(tSESSIONHDR);
  1092. Passit = FALSE;
  1093. }
  1094. else
  1095. {
  1096. status = LessThan4BytesRcvd(pLowerConn,
  1097. BytesAvailable,
  1098. BytesTaken,
  1099. ppIrp);
  1100. goto ExitRoutine;
  1101. }
  1102. }
  1103. else
  1104. {
  1105. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  1106. KdPrint(("Nbt:Got rest of PDU in indication BytesInd %X, BytesAvail %X\n",
  1107. BytesIndicated, BytesAvailable));
  1108. /* This is the remaining pdu size
  1109. */
  1110. PduSize = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  1111. /* a flag to pass the if below, since we are passing the
  1112. remaining data of a pdu to the client and we do not have
  1113. to adhere to the 128 bytes restriction.
  1114. */
  1115. PUSH_LOCATION(0x1);
  1116. if (pConnEle->JunkMsgFlag)
  1117. {
  1118. //
  1119. // in this case the client has indicated that it took the
  1120. // entire message on the previous indication, so don't
  1121. // indicate any more to it.
  1122. //
  1123. PUSH_LOCATION(0x1);
  1124. if (BytesAvailable < PduSize)
  1125. {
  1126. BTaken = BytesAvailable;
  1127. }
  1128. else
  1129. {
  1130. BTaken = PduSize;
  1131. }
  1132. pConnEle->BytesRcvd += BTaken;
  1133. if (pConnEle->BytesRcvd == pConnEle->TotalPcktLen)
  1134. {
  1135. PUSH_LOCATION(0x1);
  1136. pConnEle->BytesRcvd = 0; // reset for the next session pdu
  1137. pConnEle->JunkMsgFlag = FALSE;
  1138. }
  1139. status = STATUS_SUCCESS;
  1140. goto SkipIndication;
  1141. }
  1142. Passit = TRUE;
  1143. }
  1144. /*
  1145. be sure that there is at least 132 bytes or a whole pdu
  1146. Since a keep alive has a zero length byte, we check for
  1147. that because the 4 byte session hdr is added to the 0 length
  1148. giving 4, so a 4 byte Keep Alive pdu will pass this test.
  1149. */
  1150. if ((BytesIndicated >= NBT_INDICATE_BUFFER_SIZE) ||
  1151. (BytesIndicated >= PduSize) || Passit )
  1152. {
  1153. PUSH_LOCATION(0x2);
  1154. /*
  1155. // Indicate to the client
  1156. */
  1157. status = RcvHandlrNotOs(
  1158. ReceiveEventContext,
  1159. (PVOID)pLowerConn,
  1160. ReceiveFlags,
  1161. BytesIndicated,
  1162. BytesAvailable,
  1163. &BTaken,
  1164. pTsdu,
  1165. (PVOID)&pIrp
  1166. );
  1167. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  1168. {
  1169. ULONG RemainingPdu;
  1170. PIO_STACK_LOCATION pIrpSp;
  1171. PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
  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,pConnEle,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, pConnEle, 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, pConnectEle, 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. //********************************************************************
  2264. //********************************************************************
  2265. //
  2266. // NOTE: A copy of this procedure is in Tdihndlr.c - it is inlined for
  2267. // the NT case. Therefore, only change this procedure and then
  2268. // copy the procedure body to Tdihndlr.c
  2269. //
  2270. //
  2271. //********************************************************************
  2272. //********************************************************************
  2273. // get the ptr to the lower connection, and from that get the ptr to the
  2274. // upper connection block
  2275. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  2276. pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
  2277. //
  2278. // Session ** UP ** processing
  2279. //
  2280. *BytesTaken = 0;
  2281. pConnectEle = pLowerConn->pUpperConnection;
  2282. ASSERT(pConnectEle->pClientEle);
  2283. ASSERT(BytesIndicated >= sizeof(tSESSIONHDR));
  2284. // this routine can get called by the next part of a large pdu, so that
  2285. // we don't always started at the begining of a pdu. The Bytes Rcvd
  2286. // value is set to zero in CompletionRcv when a new pdu is expected
  2287. //
  2288. if (pConnectEle->BytesRcvd == 0)
  2289. {
  2290. if (pSessionHdr->Type == NBT_SESSION_MESSAGE)
  2291. {
  2292. //
  2293. // expecting the start of a new session Pkt, so get the length out
  2294. // of the pTsdu passed in
  2295. //
  2296. pConnectEle->TotalPcktLen = myntohl(pSessionHdr->UlongLength);
  2297. // remove the Session header by adjusting the data pointer
  2298. pTsdu = (PVOID)((PUCHAR)pTsdu + sizeof(tSESSIONHDR));
  2299. // shorten the number of bytes since we have stripped off the
  2300. // session header
  2301. BytesIndicated -= sizeof(tSESSIONHDR);
  2302. BytesAvailable -= sizeof(tSESSIONHDR);
  2303. *BytesTaken = sizeof(tSESSIONHDR);
  2304. }
  2305. //
  2306. // Session Keep Alive
  2307. //
  2308. else
  2309. if (pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE)
  2310. {
  2311. // session keep alives are simply discarded, since the act of sending
  2312. // a keep alive indicates the session is still alive, otherwise the
  2313. // transport would report an error.
  2314. // tell the transport that we took the Pdu
  2315. *BytesTaken = sizeof(tSESSIONHDR);
  2316. return(STATUS_SUCCESS);
  2317. }
  2318. else
  2319. {
  2320. // IF_DBG(NBT_DEBUG_DISCONNECT)
  2321. KdPrint(("Nbt.RcvHandlrNotOs: Unexpected SessionPdu rcvd:type=%X\n",
  2322. pSessionHdr->Type));
  2323. // ASSERT(0);
  2324. *BytesTaken = BytesIndicated;
  2325. return(STATUS_SUCCESS);
  2326. }
  2327. }
  2328. //
  2329. // check if there are any receive buffers queued against this connection
  2330. //
  2331. if (!IsListEmpty(&pConnectEle->RcvHead))
  2332. {
  2333. // get the first buffer off the receive list
  2334. pRcv = RemoveHeadList(&pConnectEle->RcvHead);
  2335. #ifndef VXD
  2336. pRcvElement = CONTAINING_RECORD(pRcv,IRP,Tail.Overlay.ListEntry);
  2337. // the cancel routine was set when this irp was posted to Nbt, so
  2338. // clear it now, since the irp is being passed to the transport
  2339. //
  2340. IoAcquireCancelSpinLock(&OldIrq);
  2341. IoSetCancelRoutine((PIRP)pRcvElement,NULL);
  2342. IoReleaseCancelSpinLock(OldIrq);
  2343. #else
  2344. pRcvElement = CONTAINING_RECORD(pRcv, RCV_CONTEXT, ListEntry ) ;
  2345. #endif
  2346. //
  2347. // this buffer is actually an Irp, so pass it back to the transport
  2348. // as a return parameter
  2349. //
  2350. *RcvBuffer = pRcvElement;
  2351. return(STATUS_MORE_PROCESSING_REQUIRED);
  2352. }
  2353. //
  2354. // No receives on this connection. Is there a receive event handler for this
  2355. // address?
  2356. //
  2357. pClientEle = pConnectEle->pClientEle;
  2358. //
  2359. // For safe
  2360. //
  2361. if (NULL == pClientEle) {
  2362. return(STATUS_DATA_NOT_ACCEPTED);
  2363. }
  2364. #ifdef VXD
  2365. //
  2366. // there is always a receive event handler in the Nt case - it may
  2367. // be the default handler, but it is there, so no need for test.
  2368. //
  2369. if (pClientEle->evReceive)
  2370. #endif
  2371. {
  2372. // check that we have not received more data than we should for
  2373. // this session Pdu. i.e. part of the next session pdu. BytesRcvd may
  2374. // have a value other than zero if the pdu has arrived in two chunks
  2375. // and the client has taken the previous one in the indication rather
  2376. // than passing back an Irp.
  2377. //
  2378. #if DBG
  2379. DebugMore = FALSE;
  2380. #endif
  2381. RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
  2382. if (BytesAvailable >= RemainingPdu)
  2383. {
  2384. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2385. KdPrint(("Nbt.RcvHandlrNotOs: More Data Recvd than expecting! Avail= %X,TotalLen= %X,state=%x\n",
  2386. BytesAvailable,pConnectEle->TotalPcktLen,pLowerConn->StateRcv));
  2387. #if DBG
  2388. DebugMore =TRUE;
  2389. #endif
  2390. // shorten the indication to the client so that they don't
  2391. // get more data than the end of the pdu
  2392. //
  2393. BytesAvailable = RemainingPdu;
  2394. if (BytesIndicated > BytesAvailable)
  2395. {
  2396. BytesIndicated = BytesAvailable;
  2397. }
  2398. //
  2399. // We always indicated at raised IRQL since we call freelockatdispatch
  2400. // below
  2401. //
  2402. ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE | TDI_RECEIVE_AT_DISPATCH_LEVEL;
  2403. }
  2404. else
  2405. {
  2406. // the transport may have has this flag on. We need to
  2407. // turn it off if the entire message is not present, where entire
  2408. // message means within the bytesAvailable length. We deliberately
  2409. // use bytesavailable so that Rdr/Srv can know that the next
  2410. // indication will be a new message if they set bytestaken to
  2411. // bytesavailable.
  2412. //
  2413. ReceiveFlags &= ~TDI_RECEIVE_ENTIRE_MESSAGE;
  2414. ReceiveFlags |= TDI_RECEIVE_AT_DISPATCH_LEVEL;
  2415. #ifndef VXD
  2416. BytesAvailable = RemainingPdu;
  2417. #endif
  2418. }
  2419. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2420. KdPrint(("Nbt.RcvHandlrNotOs: Calling Client's EventHandler <%x> BytesIndicated=<%x>, BytesAvailable=<%x>\n",
  2421. pClientEle->evReceive, BytesIndicated, BytesAvailable));
  2422. //
  2423. // NT-specific code locks pLowerConn before calling this routine,
  2424. //
  2425. CTESpinFreeAtDpc(pLowerConn);
  2426. // call the Client Event Handler
  2427. ClientBytesTaken = 0;
  2428. status = (*pClientEle->evReceive)(
  2429. pClientEle->RcvEvContext,
  2430. pConnectEle->ConnectContext,
  2431. ReceiveFlags,
  2432. BytesIndicated,
  2433. BytesAvailable,
  2434. &ClientBytesTaken,
  2435. pTsdu,
  2436. &pIrp);
  2437. CTESpinLockAtDpc(pLowerConn);
  2438. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2439. KdPrint(("Nbt.RcvHandlrNotOs: Client's EventHandler returned <%x>, BytesTaken=<%x>, pIrp=<%x>\n",
  2440. status, ClientBytesTaken, pIrp));
  2441. #if DBG
  2442. if (DebugMore)
  2443. {
  2444. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2445. KdPrint(( "Nbt.RcvHandlrNotOs: Client TOOK %X bytes, pIrp = %X,status =%X\n",
  2446. ClientBytesTaken,pIrp,status));
  2447. }
  2448. #endif
  2449. if (!pLowerConn->pUpperConnection)
  2450. {
  2451. // the connection was disconnected in the interim
  2452. // so do nothing.
  2453. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2454. {
  2455. CTEIoComplete(pIrp,STATUS_CANCELLED,0);
  2456. *BytesTaken = BytesAvailable;
  2457. return(STATUS_SUCCESS);
  2458. }
  2459. }
  2460. else
  2461. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2462. {
  2463. ASSERT(pIrp);
  2464. //
  2465. // the client may pass back a receive in the pIrp.
  2466. // In this case pIrp is a valid receive request Irp
  2467. // and the status is MORE_PROCESSING
  2468. //
  2469. // don't put these lines outside the if incase the client
  2470. // does not set ClientBytesTaken when it returns an error
  2471. // code... we don't want to use the value then
  2472. //
  2473. // count the bytes received so far. Most of the bytes
  2474. // will be received in the CompletionRcv handler in TdiHndlr.c
  2475. pConnectEle->BytesRcvd += ClientBytesTaken;
  2476. // The client has taken some of the data at least...
  2477. *BytesTaken += ClientBytesTaken;
  2478. *RcvBuffer = pIrp;
  2479. // ** FAST PATH **
  2480. return(status);
  2481. }
  2482. else
  2483. //
  2484. // no irp was returned... the client just took some of the bytes..
  2485. //
  2486. if (status == STATUS_SUCCESS)
  2487. {
  2488. // count the bytes received so far.
  2489. pConnectEle->BytesRcvd += ClientBytesTaken;
  2490. *BytesTaken += ClientBytesTaken;
  2491. //
  2492. // look at how much data was taken and adjust some counts
  2493. //
  2494. if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
  2495. {
  2496. // ** FAST PATH **
  2497. CHECK_PTR(pConnectEle);
  2498. pConnectEle->BytesRcvd = 0; // reset for the next session pdu
  2499. return(status);
  2500. }
  2501. else
  2502. if (pConnectEle->BytesRcvd > pConnectEle->TotalPcktLen)
  2503. {
  2504. //IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2505. KdPrint(("Too Many Bytes Rcvd!! Rcvd# = %d, TotalLen = %d\n",
  2506. pConnectEle->BytesRcvd,pConnectEle->TotalPcktLen));
  2507. ASSERTMSG("Nbt:Client Took Too Much Data!!!\n",0);
  2508. //
  2509. // try to recover by saying that the client took all of the
  2510. // data so at least the transport is not confused too
  2511. //
  2512. *BytesTaken = BytesIndicated;
  2513. }
  2514. else
  2515. // the client did not take all of the data so
  2516. // keep track of the fact
  2517. {
  2518. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2519. KdPrint(("NBT:Client took Indication BytesRcvd=%X, TotalLen=%X BytesAvail %X ClientTaken %X\n",
  2520. pConnectEle->BytesRcvd,
  2521. pConnectEle->TotalPcktLen,
  2522. BytesAvailable,
  2523. ClientBytesTaken));
  2524. //
  2525. // the next time the client sends down a receive buffer
  2526. // the code will pass it to the transport and decrement the
  2527. // ReceiveIndicated counter which is set in Tdihndlr.c
  2528. }
  2529. }
  2530. else
  2531. if (status == STATUS_DATA_NOT_ACCEPTED)
  2532. {
  2533. // client has not taken ANY data...
  2534. //
  2535. // In this case the *BytesTaken is set to 4, the session hdr.
  2536. // since we really have taken that data to setup the PduSize
  2537. // in the pConnEle structure.
  2538. //
  2539. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2540. KdPrint(("Nbt.RcvHandlrNotOs: Status DATA NOT ACCEPTED returned from client Avail %X %X\n",
  2541. BytesAvailable,pConnectEle));
  2542. // the code in tdihndlr.c normally looks after incrementing
  2543. // the ReceiveIndicated count for data that is not taken by
  2544. // the client, but if it is a zero length send that code cannot
  2545. // detect it, so we put code here to handle that case
  2546. //
  2547. // It is possible for the client to do a disconnect after
  2548. // we release the spin lock on pLowerConn to call the Client's
  2549. // disconnect indication. If that occurs, do not overwrite
  2550. // the StateProc with PartialRcv
  2551. //
  2552. if ((pConnectEle->TotalPcktLen == 0) &&
  2553. (pConnectEle->state == NBT_SESSION_UP))
  2554. {
  2555. SET_STATERCV_LOWER(pLowerConn, PARTIAL_RCV, PartialRcv);
  2556. CHECK_PTR(pConnectEle);
  2557. pConnectEle->ReceiveIndicated = 0; // zero bytes waiting for client
  2558. }
  2559. else
  2560. {
  2561. //
  2562. // if any bytes were taken (i.e. the session hdr) then
  2563. // return status success. (otherwise the status is
  2564. // statusNotAccpeted).
  2565. //
  2566. if (*BytesTaken)
  2567. {
  2568. status = STATUS_SUCCESS;
  2569. }
  2570. }
  2571. //
  2572. // the next time the client sends down a receive buffer
  2573. // the code will pass it to the transport and decrement this
  2574. // counter.
  2575. }
  2576. else
  2577. ASSERT(0);
  2578. return(status);
  2579. }
  2580. #ifdef VXD
  2581. //
  2582. // there is always a receive event handler in the Nt case - it may
  2583. // be the default handler, but it is there, so no need for test.
  2584. //
  2585. else
  2586. {
  2587. //
  2588. // there is no client buffer to pass the data to, so keep
  2589. // track of the fact so when the next client buffer comes down
  2590. // we can get the data from the transport.
  2591. //
  2592. KdPrint(("NBT:Client did not have a Buffer posted, rcvs indicated =%X,BytesRcvd=%X, TotalLen=%X\n",
  2593. pConnectEle->ReceiveIndicated,
  2594. pConnectEle->BytesRcvd,
  2595. pConnectEle->TotalPcktLen));
  2596. // the routine calling this one increments ReceiveIndicated and sets the
  2597. // state to PartialRcv to keep track of the fact that there is data
  2598. // waiting in the transport
  2599. //
  2600. return(STATUS_DATA_NOT_ACCEPTED);
  2601. }
  2602. #endif
  2603. }
  2604. //----------------------------------------------------------------------------
  2605. __inline
  2606. VOID
  2607. DerefLowerConnFast(
  2608. IN tLOWERCONNECTION *pLowerConn,
  2609. IN tCONNECTELE *pConnEle,
  2610. IN CTELockHandle OldIrq
  2611. )
  2612. /*++
  2613. Routine Description:
  2614. This routine dereferences the lower connection and if someone has
  2615. tried to do that during the execution of the routine that called
  2616. this one, the pConnEle is dereferenced too.
  2617. Arguments:
  2618. Return Value:
  2619. --*/
  2620. {
  2621. if (pLowerConn->RefCount > 1)
  2622. {
  2623. // This is the FAST PATH
  2624. IF_DBG(NBT_DEBUG_REF)
  2625. KdPrint(("\t--pLowerConn=<%x:%d->%d>, <%d:%s>\n",
  2626. pLowerConn,pLowerConn->RefCount,(pLowerConn->RefCount-1),__LINE__,__FILE__));
  2627. pLowerConn->RefCount--;
  2628. ASSERT (pLowerConn->References[REF_LOWC_RCV_HANDLER]--);
  2629. CTESpinFree(pLowerConn,OldIrq);
  2630. }
  2631. else
  2632. {
  2633. CTESpinFree(pLowerConn,OldIrq);
  2634. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, FALSE);
  2635. }
  2636. }
  2637. //----------------------------------------------------------------------------
  2638. VOID
  2639. DpcGetRestOfIndication(
  2640. IN PKDPC pDpc,
  2641. IN PVOID Context,
  2642. IN PVOID SystemArgument1,
  2643. IN PVOID SystemArgument2
  2644. )
  2645. /*++
  2646. Routine Description:
  2647. This routine is called when the client has been indicated with more
  2648. data than they will take and there is a rcv buffer on their RcvHead
  2649. list when completion rcv runs.
  2650. Arguments:
  2651. Return Value:
  2652. --*/
  2653. {
  2654. NTSTATUS status;
  2655. CTELockHandle OldIrq;
  2656. tCONNECTELE *pConnEle;
  2657. PIRP pIrp;
  2658. PIO_STACK_LOCATION pIrpSp;
  2659. tLOWERCONNECTION *pLowerConn=(tLOWERCONNECTION *)Context;
  2660. PLIST_ENTRY pEntry;
  2661. CTEMemFree((PVOID)pDpc);
  2662. CTESpinLockAtDpc(&NbtConfig.JointLock);
  2663. // a disconnect indication can come in any time and separate the lower and
  2664. // upper connections, so check for that
  2665. if (!pLowerConn->pUpperConnection || pLowerConn->StateRcv != PARTIAL_RCV)
  2666. {
  2667. PUSH_LOCATION(0xA4);
  2668. //
  2669. // Dereference pLowerConn
  2670. //
  2671. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, TRUE);
  2672. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2673. return;
  2674. }
  2675. CTESpinLockAtDpc(pLowerConn);
  2676. pConnEle = (tCONNECTELE *)pLowerConn->pUpperConnection;
  2677. if (!IsListEmpty(&pConnEle->RcvHead))
  2678. {
  2679. PUSH_LOCATION(0xA5);
  2680. pEntry = RemoveHeadList(&pConnEle->RcvHead);
  2681. CTESpinFreeAtDpc(pLowerConn);
  2682. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2683. pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
  2684. IoAcquireCancelSpinLock(&OldIrq);
  2685. IoSetCancelRoutine(pIrp,NULL);
  2686. IoReleaseCancelSpinLock(OldIrq);
  2687. //
  2688. // call the same routine that the client would call to post
  2689. // a recv buffer, except now we are in the PARTIAL_RCV state
  2690. // and the buffer will be passed to the transport.
  2691. //
  2692. status = NTReceive (pLowerConn->pDeviceContext, pIrp);
  2693. }
  2694. else
  2695. {
  2696. CTESpinFreeAtDpc(pLowerConn);
  2697. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2698. PUSH_LOCATION(0xA6);
  2699. }
  2700. //
  2701. // Dereference pLowerConn
  2702. //
  2703. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, FALSE);
  2704. }
  2705. //----------------------------------------------------------------------------
  2706. VOID
  2707. DpcHandleNewSessionPdu (
  2708. IN PKDPC pDpc,
  2709. IN PVOID Context,
  2710. IN PVOID SystemArgument1,
  2711. IN PVOID SystemArgument2
  2712. )
  2713. /*++
  2714. Routine Description:
  2715. This routine simply calls HandleNewSessionPdu from a Dpc started in
  2716. NewSessionCompletionRoutine.
  2717. Arguments:
  2718. Return Value:
  2719. --*/
  2720. {
  2721. CTEMemFree((PVOID)pDpc);
  2722. HandleNewSessionPdu((tLOWERCONNECTION *)Context,
  2723. PtrToUlong(SystemArgument1),
  2724. PtrToUlong(SystemArgument2));
  2725. }
  2726. //----------------------------------------------------------------------------
  2727. VOID
  2728. HandleNewSessionPdu (
  2729. IN tLOWERCONNECTION *pLowerConn,
  2730. IN ULONG Offset,
  2731. IN ULONG ToGet
  2732. )
  2733. /*++
  2734. Routine Description:
  2735. This routine handles the case when a session pdu starts in the middle of
  2736. a data indication from the transport. It gets an Irp from the free list
  2737. and formulates a receive to pass to the transport to get that data. The
  2738. assumption is that the client has taken all data preceding the next session
  2739. pdu. If the client hasn't then this routine should not be called yet.
  2740. Arguments:
  2741. Return Value:
  2742. pConnectionContext - connection context returned to the transport(connection to use)
  2743. NTSTATUS - Status of receive operation
  2744. --*/
  2745. {
  2746. NTSTATUS status;
  2747. ULONG BytesTaken;
  2748. PIRP pIrp;
  2749. PFILE_OBJECT pFileObject;
  2750. PMDL pMdl;
  2751. ULONG BytesToGet;
  2752. tCONNECTELE *pConnEle;
  2753. pIrp = NULL;
  2754. BytesTaken = 0;
  2755. // we grab the joint lock because it is needed to separate the lower and
  2756. // upper connections, so with it we can check if they have been separated.
  2757. //
  2758. CTESpinLockAtDpc(&NbtConfig.JointLock);
  2759. pConnEle = pLowerConn->pUpperConnection;
  2760. // a disconnect indication can come in any time and separate the lower and
  2761. // upper connections, so check for that
  2762. if (!pLowerConn->pUpperConnection)
  2763. {
  2764. //
  2765. // remove the reference from CompletionRcv
  2766. //
  2767. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, TRUE);
  2768. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2769. return;
  2770. }
  2771. //
  2772. // get an Irp from the list
  2773. //
  2774. status = GetIrp(&pIrp);
  2775. if (!NT_SUCCESS(status))
  2776. {
  2777. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2778. KdPrint(("Nbt:Unable to get an Irp - Closing Connection!!\n",0));
  2779. status = OutOfRsrcKill(pLowerConn);
  2780. //
  2781. // remove the reference from CompletionRcv
  2782. //
  2783. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, FALSE);
  2784. return;
  2785. }
  2786. CTESpinLockAtDpc(pLowerConn);
  2787. //
  2788. // be sure the connection has not disconnected in the meantime...
  2789. //
  2790. if (pLowerConn->State != NBT_SESSION_UP)
  2791. {
  2792. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  2793. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  2794. &pIrp->Tail.Overlay.ListEntry,
  2795. &NbtConfig.LockInfo.SpinLock);
  2796. CTESpinFreeAtDpc(pLowerConn);
  2797. //
  2798. // remove the reference from CompletionRcv
  2799. //
  2800. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER, TRUE);
  2801. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2802. return;
  2803. }
  2804. pFileObject = pLowerConn->pFileObject;
  2805. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  2806. // use the indication buffer for the receive.
  2807. pMdl = pLowerConn->pIndicateMdl;
  2808. // this flag is set below so we know if there is data in the indicate buffer
  2809. // or not.
  2810. if (Offset)
  2811. {
  2812. PVOID NewAddress;
  2813. PMDL pNewMdl;
  2814. // there is still data in the indication buffer ,so only
  2815. // fill the empty space. This means adjusting the Mdl to
  2816. // to only map the last portion of the Indication Buffer
  2817. NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pMdl)
  2818. + Offset);
  2819. // create a partial MDL so that the new data is copied after the existing data
  2820. // in the MDL.
  2821. //
  2822. // 0 for length means map the rest of the buffer
  2823. //
  2824. pNewMdl = pConnEle->pNewMdl;
  2825. IoBuildPartialMdl(pMdl,pNewMdl,NewAddress,0);
  2826. pMdl = pNewMdl;
  2827. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2828. KdPrint(("Nbt:Mapping IndicBuffer to partial Mdl Offset=%X, ToGet=%X %X\n",
  2829. Offset,ToGet,
  2830. pLowerConn));
  2831. }
  2832. else
  2833. {
  2834. CHECK_PTR(pLowerConn);
  2835. pLowerConn->BytesInIndicate = 0;
  2836. }
  2837. //
  2838. // Only get the amount of data specified, which is either the 4 byte header
  2839. // or the rest of the pdu so that we never have
  2840. // more than one session pdu in the indicate buffer.
  2841. //
  2842. BytesToGet = ToGet;
  2843. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  2844. TdiBuildReceive(
  2845. pIrp,
  2846. IoGetRelatedDeviceObject(pFileObject),
  2847. pFileObject,
  2848. NewSessionCompletionRoutine,
  2849. (PVOID)pLowerConn,
  2850. pMdl,
  2851. (ULONG)TDI_RECEIVE_NORMAL,
  2852. BytesToGet); // only ask for the number of bytes left and no more
  2853. CTESpinFreeAtDpc(pLowerConn);
  2854. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2855. CHECK_COMPLETION(pIrp);
  2856. status = IoCallDriver(IoGetRelatedDeviceObject(pFileObject),pIrp);
  2857. }
  2858. //----------------------------------------------------------------------------
  2859. NTSTATUS
  2860. NewSessionCompletionRoutine (
  2861. IN PDEVICE_OBJECT DeviceObject,
  2862. IN PIRP pIrp,
  2863. IN PVOID pContext
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. This routine handles the completion of the receive to get the remaining
  2868. data left in the transport when a session PDU starts in the middle of
  2869. an indication from the transport. This routine is run as the completion
  2870. of a recv Irp passed to the transport by NBT, to get the remainder of the
  2871. data in the transport.
  2872. The routine then calls the normal receive handler, which can either
  2873. consume the data or pass back an Irp. If an Irp is passed back then
  2874. the data is copied into that irp in this routine.
  2875. Arguments:
  2876. Return Value:
  2877. pConnectionContext - connection context returned to the transport(connection to use)
  2878. NTSTATUS - Status of receive operation
  2879. --*/
  2880. {
  2881. NTSTATUS status;
  2882. ULONG BytesTaken;
  2883. tCONNECTELE *pConnEle;
  2884. PVOID pData;
  2885. KIRQL OldIrq;
  2886. PMDL pMdl;
  2887. ULONG BytesIndicated;
  2888. ULONG BytesAvailable;
  2889. PKDPC pDpc;
  2890. tLOWERCONNECTION *pLowerConn;
  2891. ULONG Length;
  2892. ULONG PduLen;
  2893. PIRP pRetIrp;
  2894. // we grab the joint lock because it is needed to separate the lower and
  2895. // upper connections, so with it we can check if they have been separated.
  2896. //
  2897. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2898. pLowerConn = (tLOWERCONNECTION *)pContext;
  2899. pConnEle = pLowerConn->pUpperConnection;
  2900. CTESpinLockAtDpc(pLowerConn);
  2901. // a disconnect indication can come in any time and separate the lower and
  2902. // upper connections, so check for that
  2903. //
  2904. if (!pConnEle)
  2905. {
  2906. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2907. status = STATUS_UNSUCCESSFUL;
  2908. goto ExitRoutine;
  2909. }
  2910. CTESpinFreeAtDpc(&NbtConfig.JointLock);
  2911. BytesTaken = 0;
  2912. pMdl = pLowerConn->pIndicateMdl;
  2913. pData = MmGetMdlVirtualAddress(pMdl);
  2914. //
  2915. // The Indication buffer may have more data in it than what we think
  2916. // was left in the transport, because the transport may have received more
  2917. // data in the intervening time. Check for this case.
  2918. //
  2919. if (pIrp->IoStatus.Information > pConnEle->BytesInXport)
  2920. {
  2921. // no data left in transport
  2922. //
  2923. CHECK_PTR(pConnEle);
  2924. pConnEle->BytesInXport = 0;
  2925. }
  2926. else
  2927. {
  2928. //
  2929. // subtract what we just retrieved from the transport, from the count
  2930. // of data left in the transport
  2931. //
  2932. pConnEle->BytesInXport -= (ULONG)pIrp->IoStatus.Information;
  2933. }
  2934. //
  2935. // there may be data still in the indication buffer,
  2936. // so add that amount to what we just received.
  2937. //
  2938. pLowerConn->BytesInIndicate += (USHORT)pIrp->IoStatus.Information;
  2939. BytesIndicated = pLowerConn->BytesInIndicate;
  2940. // put the irp back on its free list
  2941. CHECK_PTR(pIrp);
  2942. pIrp->MdlAddress = NULL;
  2943. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  2944. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  2945. &pIrp->Tail.Overlay.ListEntry,
  2946. &NbtConfig.LockInfo.SpinLock);
  2947. //
  2948. // we need to set the bytes available to be the data in the Xport + the
  2949. // bytes in the indicate buffer, so that
  2950. // ReceiveIndicated gets set to the correct value if the client does
  2951. // not take all of data
  2952. //
  2953. BytesAvailable = pConnEle->BytesInXport + BytesIndicated;
  2954. pRetIrp = NULL;
  2955. // if the number of bytes is 4 then we just have the header and must go
  2956. // back to the transport for the rest of the pdu, or we have a keep
  2957. // alive pdu...
  2958. //
  2959. //
  2960. // This could be a session keep alive pdu so check the pdu type. Keep
  2961. // alives just go to the RcvHndlrNotOs routine and return, doing nothing.
  2962. // They have a length of zero, so the overall length is 4 and they could
  2963. // be confused for session pdus otherwise.
  2964. //
  2965. status = STATUS_SUCCESS;
  2966. if (BytesIndicated == sizeof(tSESSIONHDR))
  2967. {
  2968. PUSH_LOCATION(0x1e)
  2969. if (((tSESSIONHDR UNALIGNED *)pData)->Type == NBT_SESSION_MESSAGE)
  2970. {
  2971. // if there is still data in the transport we must send down an
  2972. // irp to get the data, however, if there is no data left in
  2973. // the transport, then the data will come up on its own, into
  2974. // the indicate_buffer case in the main Receivehandler.
  2975. //
  2976. if (pConnEle->BytesInXport)
  2977. {
  2978. PUSH_LOCATION(0x1e);
  2979. // tell the DPC routine to get the data at an offset of 4 for length Length
  2980. //
  2981. // this is the first indication to find out how large the pdu is, so
  2982. // get the length and go get the rest of the pdu.
  2983. //
  2984. Length = myntohl(((tSESSIONHDR UNALIGNED *)pData)->UlongLength);
  2985. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  2986. KdPrint(("Nbt:Got Pdu Hdr in sessioncmplionroutine, PduLen =%X\n",Length));
  2987. // it is possible to get a zero length pdu, in which case we
  2988. // do NOT need to go to the transport to get more data
  2989. //
  2990. if (Length)
  2991. {
  2992. PUSH_LOCATION(0x1e);
  2993. //
  2994. // now go get this amount of data and add it to the header
  2995. //
  2996. CTESpinFree(pLowerConn,OldIrq);
  2997. if (pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('r')))
  2998. {
  2999. // check that the pdu is not going to overflow the indicate buffer.
  3000. //
  3001. if (Length > NBT_INDICATE_BUFFER_SIZE - sizeof(tSESSIONHDR))
  3002. {
  3003. Length = NBT_INDICATE_BUFFER_SIZE - sizeof(tSESSIONHDR);
  3004. }
  3005. ASSERTMSG("Nbt:Getting ZERO bytes from Xport!!\n",Length);
  3006. KeInitializeDpc(pDpc, DpcHandleNewSessionPdu, (PVOID)pLowerConn);
  3007. KeInsertQueueDpc(pDpc, ULongToPtr(sizeof(tSESSIONHDR)), ULongToPtr(Length));
  3008. // clean up the partial mdl since we are going to turn around and reuse
  3009. // it in HandleNewSessionPdu above..
  3010. //
  3011. // THIS CALL SHOULD NOT BE NEEDED SINCE THE INDICATE BUFFER IS NON_PAGED
  3012. // POOL
  3013. // MmPrepareMdlForReuse(pConnEle->pNewMdl);
  3014. // return this status to stop to tell the io subsystem to stop processing
  3015. // this irp when we return it.
  3016. //
  3017. return(STATUS_MORE_PROCESSING_REQUIRED);
  3018. }
  3019. OutOfRsrcKill(pLowerConn);
  3020. CTESpinLock (pLowerConn,OldIrq);
  3021. status = STATUS_INSUFFICIENT_RESOURCES;
  3022. goto ExitRoutine;
  3023. }
  3024. }
  3025. }
  3026. }
  3027. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3028. KdPrint(("Nbt:NewSessComplRcv BytesinXport= %X,InIndicate=%X Indic. %X,Avail=%X %X\n",
  3029. pConnEle->BytesInXport,pLowerConn->BytesInIndicate,BytesIndicated,
  3030. BytesAvailable,pConnEle->pLowerConnId));
  3031. if (!NT_SUCCESS(pIrp->IoStatus.Status))
  3032. {
  3033. ASSERTMSG("Nbt:Not Expecting a Bad Status Code\n",0);
  3034. goto ExitRoutine;
  3035. }
  3036. //
  3037. // check if we have a whole pdu in the indicate buffer or not. IF not
  3038. // then just return and wait for more data to hit the TdiReceiveHandler
  3039. // code. This check passes KeepAlives correctly since they have a pdu
  3040. // length of 0, and adding the header gives 4, their overall length.
  3041. //
  3042. PduLen = myntohl(((tSESSIONHDR UNALIGNED *)pData)->UlongLength);
  3043. if ((BytesIndicated < PduLen + sizeof(tSESSIONHDR)) &&
  3044. (BytesIndicated != NBT_INDICATE_BUFFER_SIZE))
  3045. {
  3046. PUSH_LOCATION(0x1f);
  3047. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3048. KdPrint(("Nbt:Returning in NewSessionCompletion BytesIndicated = %X\n", BytesIndicated));
  3049. }
  3050. else
  3051. {
  3052. PUSH_LOCATION(0x20);
  3053. status = CopyDataandIndicate (NULL,
  3054. (PVOID)pLowerConn,
  3055. 0, // rcv flags
  3056. BytesIndicated,
  3057. BytesAvailable,
  3058. &BytesTaken,
  3059. pData,
  3060. (PVOID)&pRetIrp);
  3061. }
  3062. ExitRoutine:
  3063. //
  3064. // check if an irp is passed back, so we don't Deref in that case.
  3065. //
  3066. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  3067. {
  3068. //
  3069. // quickly check if we can just decrement the ref count without calling
  3070. // NBT_DEREFERENCE_LOWERCONN
  3071. //
  3072. PUSH_LOCATION(0x51);
  3073. DerefLowerConnFast(pLowerConn,pConnEle,OldIrq);
  3074. }
  3075. else
  3076. {
  3077. CTESpinFree(pLowerConn,OldIrq);
  3078. }
  3079. return(STATUS_MORE_PROCESSING_REQUIRED);
  3080. }
  3081. //----------------------------------------------------------------------------
  3082. NTSTATUS
  3083. NtBuildIndicateForReceive (
  3084. IN tLOWERCONNECTION *pLowerConn,
  3085. IN ULONG Length,
  3086. OUT PVOID *ppIrp
  3087. )
  3088. /*++
  3089. Routine Description:
  3090. This routine sets up the indicate buffer to get data from the transport
  3091. when the indicate buffer already has some data in it. A partial MDL is
  3092. built and the attached to the irp.
  3093. before we indicate.
  3094. Arguments:
  3095. Return Value:
  3096. NTSTATUS - Status of receive operation
  3097. --*/
  3098. {
  3099. NTSTATUS status;
  3100. PIRP pIrp;
  3101. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  3102. PIO_STACK_LOCATION pIrpSp;
  3103. tCONNECTELE *pConnEle;
  3104. PMDL pNewMdl;
  3105. PVOID NewAddress;
  3106. //
  3107. // get an Irp from the list
  3108. //
  3109. status = GetIrp(&pIrp);
  3110. if (!NT_SUCCESS(status))
  3111. {
  3112. KdPrint(("NBT:Unable to get Irp, Kill connection\n"));
  3113. CTESpinFreeAtDpc(pLowerConn);
  3114. OutOfRsrcKill(pLowerConn);
  3115. CTESpinLockAtDpc(pLowerConn);
  3116. return(STATUS_INSUFFICIENT_RESOURCES);
  3117. }
  3118. pConnEle= pLowerConn->pUpperConnection;
  3119. NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl)
  3120. + pLowerConn->BytesInIndicate);
  3121. // create a partial MDL so that the new data is copied after the existing data
  3122. // in the MDL.
  3123. //
  3124. // 0 for length means map the rest of the buffer
  3125. //
  3126. pNewMdl = pConnEle->pNewMdl;
  3127. IoBuildPartialMdl(pLowerConn->pIndicateMdl,pNewMdl,NewAddress,0);
  3128. ASSERT (pLowerConn->pFileObject->Type == IO_TYPE_FILE);
  3129. TdiBuildReceive(
  3130. pIrp,
  3131. IoGetRelatedDeviceObject(pLowerConn->pFileObject),
  3132. pLowerConn->pFileObject,
  3133. NewSessionCompletionRoutine,
  3134. (PVOID)pLowerConn,
  3135. pNewMdl,
  3136. (ULONG)TDI_RECEIVE_NORMAL,
  3137. Length);
  3138. //
  3139. // we need to set the next Irp stack location because this irp is returned
  3140. // as a return parameter rather than being passed through IoCallDriver
  3141. // which increments the stack location itself
  3142. //
  3143. ASSERT(pIrp->CurrentLocation > 1);
  3144. IoSetNextIrpStackLocation(pIrp);
  3145. *ppIrp = (PVOID)pIrp;
  3146. return(STATUS_SUCCESS);
  3147. }
  3148. //----------------------------------------------------------------------------
  3149. NTSTATUS
  3150. NtBuildIrpForReceive (
  3151. IN tLOWERCONNECTION *pLowerConn,
  3152. IN ULONG Length,
  3153. OUT PVOID *ppIrp
  3154. )
  3155. /*++
  3156. Routine Description:
  3157. This routine gets an Irp to be used to receive data and hooks the indication
  3158. Mdl to it, so we can accumulate at least 128 bytes of data for the client
  3159. before we indicate.
  3160. Arguments:
  3161. Return Value:
  3162. NTSTATUS - Status of receive operation
  3163. --*/
  3164. {
  3165. NTSTATUS status;
  3166. PIRP pIrp;
  3167. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  3168. PIO_STACK_LOCATION pIrpSp;
  3169. //
  3170. // get an Irp from the list
  3171. //
  3172. status = GetIrp(&pIrp);
  3173. if (!NT_SUCCESS(status))
  3174. {
  3175. KdPrint(("NBT:Unable to get Irp, Kill connection\n"));
  3176. return(STATUS_INSUFFICIENT_RESOURCES);
  3177. }
  3178. CHECK_PTR(pLowerConn);
  3179. pLowerConn->BytesInIndicate = 0;
  3180. ASSERT (pLowerConn->pFileObject->Type == IO_TYPE_FILE);
  3181. TdiBuildReceive(
  3182. pIrp,
  3183. IoGetRelatedDeviceObject(pLowerConn->pFileObject),
  3184. pLowerConn->pFileObject,
  3185. NewSessionCompletionRoutine,
  3186. (PVOID)pLowerConn,
  3187. pLowerConn->pIndicateMdl,
  3188. (ULONG)TDI_RECEIVE_NORMAL,
  3189. Length);
  3190. //
  3191. // we need to set the next Irp stack location because this irp is returned
  3192. // as a return parameter rather than being passed through IoCallDriver
  3193. // which increments the stack location itself
  3194. //
  3195. ASSERT(pIrp->CurrentLocation > 1);
  3196. IoSetNextIrpStackLocation(pIrp);
  3197. *ppIrp = (PVOID)pIrp;
  3198. return(STATUS_SUCCESS);
  3199. }
  3200. #pragma inline_depth(0)
  3201. //----------------------------------------------------------------------------
  3202. NTSTATUS
  3203. CopyDataandIndicate(
  3204. IN PVOID ReceiveEventContext,
  3205. IN PVOID ConnectionContext,
  3206. IN USHORT ReceiveFlags,
  3207. IN ULONG BytesIndicated,
  3208. IN ULONG BytesAvailable,
  3209. OUT PULONG BytesTaken,
  3210. IN PVOID pTsdu,
  3211. OUT PIRP *ppIrp
  3212. )
  3213. /*++
  3214. Routine Description:
  3215. This routine combines data indicated with the indicate buffer to
  3216. indicate the total to the client. Any bytes Indicated are those bytes
  3217. in the indicate buffer. Bytes available adds in any bytes in the transport.
  3218. The idea here is to copy as much as possible from the indicate buffer and
  3219. then pass back an irp if there is still more data in the transport. If
  3220. no data left in the transport, this routine completes the client irp and
  3221. returns STATUS_SUCCESS.
  3222. Arguments:
  3223. Return Value:
  3224. NTSTATUS - Status of receive operation
  3225. --*/
  3226. {
  3227. NTSTATUS status;
  3228. tLOWERCONNECTION *pLowerConn;
  3229. tCONNECTELE *pConnEle;
  3230. ULONG BytesCopied;
  3231. ULONG Indicated;
  3232. ULONG Available;
  3233. ULONG Taken;
  3234. ULONG AmountAlreadyInIndicateBuffer;
  3235. PVOID pBuffer;
  3236. PIRP pIrp;
  3237. BOOLEAN bReIndicate=FALSE;
  3238. ULONG RemainingPdu;
  3239. ULONG ToCopy;
  3240. PKDPC pDpc;
  3241. ULONG SaveInXport;
  3242. ULONG PduSize;
  3243. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  3244. pConnEle = pLowerConn->pUpperConnection;
  3245. AmountAlreadyInIndicateBuffer = pLowerConn->BytesInIndicate;
  3246. //
  3247. // set the parameters for the call to the TdiReceiveHandler routine
  3248. //
  3249. Indicated = BytesIndicated;
  3250. Available = BytesAvailable;
  3251. Taken = 0;
  3252. // ASSERT(pLowerConn->StateRcv == INDICATE_BUFFER);
  3253. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3254. KdPrint(("Nbt:Amount In Indicate = %X\n",AmountAlreadyInIndicateBuffer));
  3255. // now that we have 128 bytes (plus the session hdr = 132 total) we
  3256. // can indicate to the client
  3257. pBuffer = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
  3258. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3259. KdPrint(("Nbt:FromCopyData, BytesAvail= %X,BytesInd= %X,BytesRcvd= %X,Amount=%X, %X,state=%X,RcvEC=%X\n",
  3260. Available,Indicated,pConnEle->BytesRcvd,
  3261. AmountAlreadyInIndicateBuffer,pLowerConn,pLowerConn->StateRcv,
  3262. ReceiveEventContext));
  3263. pIrp = NULL;
  3264. //
  3265. // Reset this count so that the routine processes the Session header correctly
  3266. //
  3267. CHECK_PTR(pConnEle);
  3268. pConnEle->BytesRcvd = 0;
  3269. PUSH_LOCATION(0x21);
  3270. status = RcvHandlrNotOs(
  3271. NULL,
  3272. ConnectionContext,
  3273. ReceiveFlags,
  3274. Indicated,
  3275. Available,
  3276. &Taken,
  3277. pBuffer,
  3278. (PVOID)&pIrp
  3279. );
  3280. //
  3281. // if the connection has disonnected, then just return
  3282. //
  3283. if (!pLowerConn->pUpperConnection)
  3284. {
  3285. *BytesTaken = BytesAvailable;
  3286. return(STATUS_SUCCESS);
  3287. }
  3288. // do not use pConnEle->TotalPcktLen here becauase it won't be set for
  3289. // keep alives - must use actual buffer to get length.
  3290. PduSize = myntohl(((tSESSIONHDR UNALIGNED *)pBuffer)->UlongLength) + sizeof(tSESSIONHDR);
  3291. RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
  3292. if (Taken <= pLowerConn->BytesInIndicate)
  3293. {
  3294. pLowerConn->BytesInIndicate -= (USHORT)Taken;
  3295. }
  3296. else
  3297. {
  3298. pLowerConn->BytesInIndicate = 0;
  3299. }
  3300. if (pIrp)
  3301. {
  3302. PIO_STACK_LOCATION pIrpSp;
  3303. PTDI_REQUEST_KERNEL_RECEIVE pParams;
  3304. ULONG ClientRcvLen;
  3305. PUSH_LOCATION(0x22);
  3306. //
  3307. // BytesInXport will be recalculated by ProcessIrp based on BytesAvailable
  3308. // and the ClientRcvLength, so set it to 0 here.
  3309. //
  3310. SaveInXport = pConnEle->BytesInXport;
  3311. CHECK_PTR(pConnEle);
  3312. pConnEle->BytesInXport = 0;
  3313. status = ProcessIrp(pLowerConn,
  3314. pIrp,
  3315. pBuffer,
  3316. &Taken,
  3317. Indicated,
  3318. Available);
  3319. //
  3320. // copy the data in the indicate buffer that was not taken by the client
  3321. // into the MDL and then update the bytes taken and pass the irp on downwar
  3322. // to the transport
  3323. //
  3324. ToCopy = Indicated - Taken;
  3325. // the Next stack location has the correct info in it because we
  3326. // called TdiRecieveHandler with a null ReceiveEventContext,
  3327. // so that routine does not increment the stack location
  3328. //
  3329. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  3330. pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
  3331. ClientRcvLen = pParams->ReceiveLength;
  3332. // did the client's Pdu fit entirely into the indication buffer?
  3333. //
  3334. if (ClientRcvLen <= ToCopy)
  3335. {
  3336. PUSH_LOCATION(0x23);
  3337. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3338. KdPrint(("Nbt:Took some(or all) RemainingPdu= %X, ClientRcvLen= %X,InXport=%X %X\n",
  3339. RemainingPdu,ClientRcvLen,pConnEle->BytesInXport,pLowerConn));
  3340. // if ProcessIrp has recalculated the bytes in the Xport
  3341. // then set it back to where it should be, Since ProcessIrp will
  3342. // put all not taken bytes as bytes in the transport - but some
  3343. // of the bytes are still in the indicate buffer.
  3344. //
  3345. pConnEle->BytesInXport = SaveInXport;
  3346. // it could be a zero length send where the client returns a null
  3347. // mdl, or the client returns an mdl and the RcvLen is really zero.
  3348. //
  3349. if (pIrp->MdlAddress && ClientRcvLen)
  3350. {
  3351. TdiCopyBufferToMdl(pBuffer, // indicate buffer
  3352. Taken, // src offset
  3353. ClientRcvLen,
  3354. pIrp->MdlAddress,
  3355. 0, // dest offset
  3356. &BytesCopied);
  3357. }
  3358. else
  3359. BytesCopied = 0;
  3360. //
  3361. // check for data still in the transport - subtract data copied to
  3362. // Irp, since Taken was already subtracted.
  3363. //
  3364. pLowerConn->BytesInIndicate -= (USHORT)BytesCopied;
  3365. *BytesTaken = Taken + BytesCopied;
  3366. ASSERT(BytesCopied == ClientRcvLen);
  3367. // the client has received all of the data, so complete his irp
  3368. //
  3369. pIrp->IoStatus.Information = BytesCopied;
  3370. pIrp->IoStatus.Status = STATUS_SUCCESS;
  3371. // since we are completing it and TdiRcvHandler did not set the next
  3372. // one.
  3373. //
  3374. ASSERT(pIrp->CurrentLocation > 1);
  3375. // since we are completing the irp here, no need to call
  3376. // this, because it will complete through completionrcv.
  3377. IoSetNextIrpStackLocation(pIrp);
  3378. // there should not be any data in the indicate buffer since it
  3379. // only holds either 132 bytes or a whole pdu unless the client
  3380. // receive length is too short...
  3381. //
  3382. if (pLowerConn->BytesInIndicate)
  3383. {
  3384. PUSH_LOCATION(0x23);
  3385. // when the irp goes through completionRcv it should set the
  3386. // state to PartialRcv and the next posted buffer from
  3387. // the client should pickup this data.
  3388. CopyToStartofIndicate(pLowerConn,(Taken+BytesCopied));
  3389. }
  3390. else
  3391. {
  3392. //
  3393. // this will complete through CompletionRcv and for that
  3394. // reason it will get any more data left in the transport. The
  3395. // Completion routine will set the correct state for the rcv when
  3396. // it processes this Irp ( to INDICATED, if needed). ProcessIrp
  3397. // may have set ReceiveIndicated, so that CompletionRcv will
  3398. // set the state to PARTIAL_RCV when it runs.
  3399. //
  3400. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  3401. }
  3402. CTESpinFreeAtDpc(pLowerConn);
  3403. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  3404. CTESpinLockAtDpc(pLowerConn);
  3405. //
  3406. // this was undone by CompletionRcv, so redo them, since the
  3407. // caller will undo them again.
  3408. //
  3409. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  3410. return(STATUS_SUCCESS);
  3411. }
  3412. else
  3413. {
  3414. PUSH_LOCATION(0x24);
  3415. //
  3416. // there is still data that we need to get to fill the PDU. There
  3417. // may be more data left in the transport or not after the irp is
  3418. // filled.
  3419. // In either case the Irps' Mdl must be adjusted to account for
  3420. // filling part of it.
  3421. //
  3422. TdiCopyBufferToMdl(pBuffer, // IndicateBuffer
  3423. Taken, // src offset
  3424. ToCopy,
  3425. pIrp->MdlAddress,
  3426. 0, // dest offset
  3427. &BytesCopied);
  3428. //
  3429. // save the Mdl so we can reconstruct things later
  3430. //
  3431. pLowerConn->pMdl = pIrp->MdlAddress;
  3432. pConnEle->pNextMdl = pIrp->MdlAddress;
  3433. ASSERT(pIrp->MdlAddress);
  3434. //
  3435. // The irp is being passed back to the transport, so we NULL
  3436. // our ptr to it so we don't try to cancel it on a disconnect
  3437. //
  3438. CHECK_PTR(pConnEle);
  3439. pConnEle->pIrpRcv = NULL;
  3440. // Adjust the number of bytes in the Mdl chain so far since the
  3441. // completion routine will only count the bytes filled in by the
  3442. // transport
  3443. //
  3444. pConnEle->BytesRcvd += BytesCopied;
  3445. *BytesTaken = BytesIndicated;
  3446. //
  3447. // clear the number of bytes in the indicate buffer since the client
  3448. // has taken more than the data left in the Indicate buffer
  3449. //
  3450. CHECK_PTR(pLowerConn);
  3451. pLowerConn->BytesInIndicate = 0;
  3452. // decrement the client rcv len by the amount already put into the
  3453. // client Mdl
  3454. //
  3455. ClientRcvLen -= BytesCopied;
  3456. //
  3457. // if ProcessIrp did recalculate the bytes in the transport
  3458. // then set back to what it was. Process irp will do this
  3459. // recalculation if the clientrcv buffer is too short only.
  3460. //
  3461. pConnEle->BytesInXport = SaveInXport;
  3462. //
  3463. // adjust the number of bytes downward due to the client rcv
  3464. // buffer
  3465. //
  3466. if (ClientRcvLen < SaveInXport)
  3467. {
  3468. PUSH_LOCATION(0x24);
  3469. pConnEle->BytesInXport -= ClientRcvLen;
  3470. }
  3471. else
  3472. {
  3473. pConnEle->BytesInXport = 0;
  3474. }
  3475. // ProcessIrp will set bytesinXport and ReceiveIndicated - since
  3476. // the indicate buffer is empty that calculation of BytesInXport
  3477. // will be correct.
  3478. //
  3479. // We MUST set the state to FILL_IRP so that completion Rcv
  3480. // undoes the partial MDL stuff - i.e. it puts the original
  3481. // MdlAddress in the Irp, rather than the partial Mdl address.
  3482. // CompletionRcv will set the state to partial Rcv if ReceiveIndicated
  3483. // is not zero.
  3484. //
  3485. SET_STATERCV_LOWER(pLowerConn, FILL_IRP, FillIrp);
  3486. // the client is going to take more data from the transport with
  3487. // this Irp. Set the new Rcv Length that accounts for the data just
  3488. // copied to the Irp.
  3489. //
  3490. pParams->ReceiveLength = ClientRcvLen;
  3491. // keep track of data in MDL so we know when it is full and we need to
  3492. // return it to the user - ProcessIrp set it to ClientRcvLen, so
  3493. // shorten it here.
  3494. //
  3495. pConnEle->FreeBytesInMdl -= BytesCopied;
  3496. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3497. KdPrint(("Nbt:ClientRcvLen = %X, LeftinXport= %X RemainingPdu= %X %X\n",ClientRcvLen,
  3498. pConnEle->BytesInXport,RemainingPdu,pLowerConn));
  3499. // Build a partial Mdl to represent the client's Mdl chain since
  3500. // we have copied data to it, and the transport must copy
  3501. // more data to it after that data.
  3502. //
  3503. MakePartialMdl(pConnEle,pIrp,BytesCopied);
  3504. *ppIrp = pIrp;
  3505. // increments the stack location, since TdiReceiveHandler did not.
  3506. //
  3507. if (ReceiveEventContext)
  3508. {
  3509. ASSERT(pIrp->CurrentLocation > 1);
  3510. IoSetNextIrpStackLocation(pIrp);
  3511. return(STATUS_MORE_PROCESSING_REQUIRED);
  3512. }
  3513. else
  3514. {
  3515. // pass the Irp to the transport since we were called from
  3516. // NewSessionCompletionRoutine
  3517. //
  3518. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3519. KdPrint(("Nbt:Calling IoCallDriver\n"));
  3520. ASSERT(pIrp->CurrentLocation > 1);
  3521. CTESpinFreeAtDpc(pLowerConn);
  3522. CHECK_COMPLETION(pIrp);
  3523. ASSERT (pLowerConn->pFileObject->Type == IO_TYPE_FILE);
  3524. IoCallDriver(IoGetRelatedDeviceObject(pLowerConn->pFileObject),pIrp);
  3525. CTESpinLockAtDpc(pLowerConn);
  3526. return(STATUS_MORE_PROCESSING_REQUIRED);
  3527. }
  3528. }
  3529. }
  3530. else
  3531. {
  3532. PUSH_LOCATION(0x54);
  3533. //
  3534. // no Irp passed back, the client just took some or all of the data
  3535. //
  3536. *BytesTaken = Taken;
  3537. pLowerConn->BytesRcvd += Taken - sizeof(tSESSIONHDR);
  3538. ASSERT(*BytesTaken < 0x7FFFFFFF );
  3539. //
  3540. // if more than the indicate buffer is taken, then the client
  3541. // is probably trying to say it doesn't want any more of the
  3542. // message.
  3543. //
  3544. if (Taken > BytesIndicated)
  3545. {
  3546. //
  3547. // in this case the client has taken more than the indicated.
  3548. // We set bytesavailable to the message length in RcvHndlrNotOs,
  3549. // so the client has probably said BytesTaken=BytesAvailable.
  3550. // So kill the connection
  3551. // because we have no way of handling this case here, since
  3552. // part of the message may still be in the transport, and we
  3553. // might have to send the indicate buffer down there multiple
  3554. // times to get all of it...a mess! The Rdr only sets bytestaken =
  3555. // bytesAvailable under select error conditions anyway.
  3556. //
  3557. CTESpinFreeAtDpc(pLowerConn);
  3558. OutOfRsrcKill(pLowerConn);
  3559. CTESpinLockAtDpc(pLowerConn);
  3560. *BytesTaken = BytesAvailable;
  3561. }
  3562. else if (pLowerConn->StateRcv == PARTIAL_RCV)
  3563. {
  3564. // this may be a zero length send -that the client has
  3565. // decided not to accept. If so then the state will be set
  3566. // to PartialRcv. In this case do NOT go down to the transport
  3567. // and get the rest of the data, but wait for the client
  3568. // to post a rcv buffer.
  3569. //
  3570. PUSH_LOCATION(0x54);
  3571. return(STATUS_SUCCESS);
  3572. }
  3573. else if (Taken == PduSize)
  3574. {
  3575. //
  3576. // Must have taken all of the pdu data, so check for
  3577. // more data available - if so send down the indicate
  3578. // buffer to get it.
  3579. //
  3580. if (pConnEle->BytesInXport)
  3581. {
  3582. PUSH_LOCATION(0x28);
  3583. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3584. KdPrint(("Nbt:CopyData BytesInXport= %X, %X\n",pConnEle->BytesInXport,
  3585. pLowerConn));
  3586. //
  3587. // there is still data in the transport so Q a Dpc to use
  3588. // the indicate buffer to get the data
  3589. //
  3590. pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('s'));
  3591. if (pDpc)
  3592. {
  3593. KeInitializeDpc(pDpc, DpcHandleNewSessionPdu, (PVOID)pLowerConn);
  3594. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, IndicateBuffer);
  3595. // get just the header first to see how large the pdu is
  3596. //
  3597. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_RCV_HANDLER);
  3598. KeInsertQueueDpc(pDpc,NULL,(PVOID)sizeof(tSESSIONHDR));
  3599. }
  3600. else
  3601. {
  3602. CTESpinFreeAtDpc(pLowerConn);
  3603. OutOfRsrcKill(pLowerConn);
  3604. CTESpinLockAtDpc(pLowerConn);
  3605. }
  3606. }
  3607. else
  3608. {
  3609. PUSH_LOCATION(0x29);
  3610. //
  3611. // clear the flag saying that we are using the indicate buffer
  3612. //
  3613. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  3614. }
  3615. PUSH_LOCATION(0x2a);
  3616. return(STATUS_SUCCESS);
  3617. }
  3618. else
  3619. {
  3620. //
  3621. // the client may have taken all the data in the
  3622. // indication!!, in which case return status success
  3623. // Note: that we check bytes available here not bytes
  3624. // indicated - since the client could take all indicated
  3625. // data but still leave data in the transport. If the client
  3626. // got told there was more available but only took the indicated,
  3627. // the we need to do the else and track ReceiveIndicated, but if
  3628. // Indicated == Available, then we take the if and wait for
  3629. // another indication from the transport.
  3630. //
  3631. if (Taken == BytesAvailable)
  3632. {
  3633. PUSH_LOCATION(0x4);
  3634. status = STATUS_SUCCESS;
  3635. }
  3636. else
  3637. {
  3638. // did not take all of the data in the Indication
  3639. //
  3640. PUSH_LOCATION(0x2b);
  3641. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  3642. KdPrint(("Nbt:Took Part of indication... BytesRemaining= %X, LeftInXport= %X, %X\n",
  3643. pLowerConn->BytesInIndicate,pConnEle->BytesInXport,pLowerConn));
  3644. //
  3645. // The amount of data Indicated to the client should not exceed
  3646. // the Pdu size, so check that, since this routine could get
  3647. // called with bytesAvailable > than the Pdu size.
  3648. //
  3649. // That is checked above where we check if Taken > BytesIndicated.
  3650. SaveInXport = pConnEle->BytesInXport;
  3651. ASSERT(Taken <= PduSize);
  3652. status = ClientTookSomeOfTheData(pLowerConn,
  3653. Indicated,
  3654. Available,
  3655. Taken,
  3656. PduSize);
  3657. //
  3658. // Since the data may be divided between some in the transport
  3659. // and some in the indicate buffer do not let ClientTookSomeOf...
  3660. // recalculate the amount in the transport, since it assumes all
  3661. // untaken data is in the transport. Since the client did not
  3662. // take of the indication, the Bytes in Xport have not changed.
  3663. //
  3664. pConnEle->BytesInXport = SaveInXport;
  3665. //
  3666. // need to move the data forward in the indicate buffer so that
  3667. // it begins at the start of the buffer
  3668. //
  3669. if (Taken)
  3670. {
  3671. CopyToStartofIndicate(pLowerConn,Taken);
  3672. }
  3673. }
  3674. }
  3675. }
  3676. return(STATUS_SUCCESS);
  3677. }
  3678. //----------------------------------------------------------------------------
  3679. NTSTATUS
  3680. TdiConnectHandler (
  3681. IN PVOID pConnectEventContext,
  3682. IN int RemoteAddressLength,
  3683. IN PVOID pRemoteAddress,
  3684. IN int UserDataLength,
  3685. IN PVOID pUserData,
  3686. IN int OptionsLength,
  3687. IN PVOID pOptions,
  3688. OUT CONNECTION_CONTEXT *pConnectionContext,
  3689. OUT PIRP *ppAcceptIrp
  3690. )
  3691. /*++
  3692. Routine Description:
  3693. This routine is connect event handler. It is invoked when a request for
  3694. a connection has been received by the provider. NBT accepts the connection
  3695. on one of its connections in its LowerConnFree list
  3696. Initially a TCP connection is setup with this port. Then a Session Request
  3697. packet is sent across the connection to indicate the name of the destination
  3698. process. This packet is received in the RcvHandler.
  3699. For message-only mode, make session establishment automatic without the exchange of
  3700. messages. In this case, the best way to do this is to force the code through its paces.
  3701. The code path for "inbound" setup includes AcceptCompletionRoutine, Inbound, and
  3702. CompleteSessionSetup. We do this by creating a fake session request and feeding it into
  3703. the state machine.
  3704. As part of connection/session establishment, Netbt must notify
  3705. the consumer. Normally this is done after connection establishment when the session request
  3706. comes in. We must move this process up so that the consumer gets his notification and
  3707. yah/nay opportunity during connection acceptance, so we gets a chance to reject the connection.
  3708. Arguments:
  3709. pConnectEventContext - the context passed to the transport when this event was setup
  3710. RemoteAddressLength - the length of the source address (4 bytes for IP)
  3711. pRemoteAddress - a ptr to the source address
  3712. UserDataLength - the number of bytes of user data - includes the session Request hdr
  3713. pUserData - ptr the the user data passed in
  3714. OptionsLength - number of options to pass in
  3715. pOptions - ptr to the options
  3716. Return Value:
  3717. pConnectionContext - connection context returned to the transport(connection to use)
  3718. NTSTATUS - Status of receive operation
  3719. --*/
  3720. {
  3721. NTSTATUS status;
  3722. PFILE_OBJECT pFileObject;
  3723. PIRP pRequestIrp;
  3724. CONNECTION_CONTEXT pConnectionId;
  3725. tDEVICECONTEXT *pDeviceContext;
  3726. *pConnectionContext = NULL;
  3727. // convert the context value into the device context record ptr
  3728. pDeviceContext = (tDEVICECONTEXT *)pConnectEventContext;
  3729. IF_DBG(NBT_DEBUG_TDIHNDLR)
  3730. KdPrint(("pDeviceContxt = %X ConnectEv = %X",pDeviceContext,pConnectEventContext));
  3731. ASSERTMSG("Bad Device context passed to the Connection Event Handler",
  3732. pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
  3733. // get an Irp from the list
  3734. status = GetIrp(&pRequestIrp);
  3735. if (!NT_SUCCESS(status))
  3736. {
  3737. return(STATUS_DATA_NOT_ACCEPTED);
  3738. }
  3739. // call the non-OS specific routine to find a free connection.
  3740. status = ConnectHndlrNotOs(
  3741. pConnectEventContext,
  3742. RemoteAddressLength,
  3743. pRemoteAddress,
  3744. UserDataLength,
  3745. pUserData,
  3746. &pConnectionId);
  3747. if (!NT_SUCCESS(status))
  3748. {
  3749. IF_DBG(NBT_DEBUG_TDIHNDLR)
  3750. KdPrint(("NO FREE CONNECTIONS in connect handler\n"));
  3751. // put the Irp back on its free list
  3752. //
  3753. REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
  3754. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  3755. &pRequestIrp->Tail.Overlay.ListEntry,
  3756. &NbtConfig.LockInfo.SpinLock);
  3757. NbtTrace(NBT_TRACE_INBOUND, ("ConnectHndlrNotOs return %!status!", status));
  3758. return(STATUS_DATA_NOT_ACCEPTED);
  3759. }
  3760. #ifdef _NETBIOSLESS
  3761. //
  3762. // MessageOnly mode. Establish session automatically.
  3763. //
  3764. // ******************************************************************************************
  3765. if (IsDeviceNetbiosless(pDeviceContext))
  3766. {
  3767. status = PerformInboundProcessing (pDeviceContext,
  3768. (tLOWERCONNECTION *) pConnectionId,
  3769. pRemoteAddress);
  3770. if (!NT_SUCCESS(status))
  3771. {
  3772. // IF_DBG(NBT_DEBUG_TDIHNDLR)
  3773. KdPrint(("MessageOnly connect processing rejected with status 0x%x\n", status));
  3774. // put the Irp back on its free list
  3775. //
  3776. REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
  3777. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  3778. &pRequestIrp->Tail.Overlay.ListEntry,
  3779. &NbtConfig.LockInfo.SpinLock);
  3780. NbtTrace(NBT_TRACE_INBOUND, ("PerformInboundProecessing return %!status!", status));
  3781. return(STATUS_DATA_NOT_ACCEPTED);
  3782. }
  3783. }
  3784. // ******************************************************************************************
  3785. //
  3786. //
  3787. #endif
  3788. pFileObject = ((tLOWERCONNECTION *)pConnectionId)->pFileObject;
  3789. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  3790. TdiBuildAccept(
  3791. pRequestIrp,
  3792. IoGetRelatedDeviceObject(pFileObject),
  3793. pFileObject,
  3794. AcceptCompletionRoutine,
  3795. (PVOID)pConnectionId,
  3796. NULL,
  3797. NULL);
  3798. // we need to null the MDL address because the transport KEEPS trying to
  3799. // release buffers!! which do not exist!!!
  3800. //
  3801. CHECK_PTR(pRequestIrp);
  3802. pRequestIrp->MdlAddress = NULL;
  3803. // return the connection id to accept the connect indication on.
  3804. *pConnectionContext = (CONNECTION_CONTEXT)pConnectionId;
  3805. *ppAcceptIrp = pRequestIrp;
  3806. //
  3807. // make the next stack location the current one. Normally IoCallDriver
  3808. // would do this but we are not going through IoCallDriver here, since the
  3809. // Irp is just passed back with Connect Indication.
  3810. //
  3811. ASSERT(pRequestIrp->CurrentLocation > 1);
  3812. IoSetNextIrpStackLocation(pRequestIrp);
  3813. return(STATUS_MORE_PROCESSING_REQUIRED);
  3814. }
  3815. #ifdef _NETBIOSLESS
  3816. //----------------------------------------------------------------------------
  3817. static void
  3818. Inet_ntoa_nb(
  3819. ULONG Address,
  3820. PCHAR Buffer
  3821. )
  3822. /*++
  3823. Routine Description:
  3824. This routine converts an IP address into its "dotted quad" representation. The IP address is
  3825. expected to be in network byte order. No attempt is made to handle the other dotted notions as
  3826. defined in in.h. No error checking is done: all address values are permissible including 0
  3827. and -1. The output string is blank padded to 16 characters to make the name look like a netbios
  3828. name.
  3829. The string representation is in ANSI, not UNICODE.
  3830. The caller must allocate the storage, which should be 16 characters.
  3831. Arguments:
  3832. Address - IP address in network byte order
  3833. Buffer - Pointer to buffer to receive string representation, ANSI
  3834. Return Value:
  3835. void
  3836. --*/
  3837. {
  3838. ULONG i;
  3839. UCHAR byte, c0, c1, c2;
  3840. PCHAR p = Buffer;
  3841. for( i = 0; i < 4; i++ )
  3842. {
  3843. byte = (UCHAR) (Address & 0xff);
  3844. c0 = byte % 10;
  3845. byte /= 10;
  3846. c1 = byte % 10;
  3847. byte /= 10;
  3848. c2 = byte;
  3849. if (c2 != 0)
  3850. {
  3851. *p++ = c2 + '0';
  3852. *p++ = c1 + '0';
  3853. } else if (c1 != 0)
  3854. {
  3855. *p++ = c1 + '0';
  3856. }
  3857. *p++ = c0 + '0';
  3858. if (i != 3)
  3859. *p++ = '.';
  3860. Address >>= 8;
  3861. }
  3862. // space pad up to 16 characters
  3863. while (p < (Buffer + 16))
  3864. {
  3865. *p++ = ' ';
  3866. }
  3867. } // Inet_ntoa1
  3868. //----------------------------------------------------------------------------
  3869. NTSTATUS
  3870. PerformInboundProcessing(
  3871. tDEVICECONTEXT *pDeviceContext,
  3872. tLOWERCONNECTION *pLowerConn,
  3873. PTA_IP_ADDRESS pIpAddress
  3874. )
  3875. /*++
  3876. Routine Description:
  3877. This routine is called by the connection handler to force the state machine through a session
  3878. establishment even though no message has been received. We create a session request and feed
  3879. it into Inbound processing. Inbound will find the listening consumer and give him a chance to
  3880. accept.
  3881. Arguments:
  3882. pDeviceContext -
  3883. pLowerConn -
  3884. pIpAddress - Ip address of the source of the connect request
  3885. Return Value:
  3886. NTSTATUS -
  3887. --*/
  3888. {
  3889. ULONG status;
  3890. ULONG BytesTaken;
  3891. USHORT sLength;
  3892. tSESSIONREQ *pSessionReq = NULL;
  3893. PUCHAR pCopyTo;
  3894. CHAR SourceName[16];
  3895. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3896. KdPrint(("Nbt.TdiConnectHandler: skipping session setup\n"));
  3897. if (pIpAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)
  3898. {
  3899. return STATUS_INVALID_ADDRESS_COMPONENT;
  3900. }
  3901. Inet_ntoa_nb( pIpAddress->Address[0].Address[0].in_addr, SourceName );
  3902. // the length is the 4 byte session hdr length + the half ascii calling
  3903. // and called names + the scope length times 2, one for each name
  3904. //
  3905. sLength = (USHORT) (sizeof(tSESSIONREQ) + (NETBIOS_NAME_SIZE << 2) + (NbtConfig.ScopeLength <<1));
  3906. pSessionReq = (tSESSIONREQ *)NbtAllocMem(sLength,NBT_TAG('G'));
  3907. if (!pSessionReq)
  3908. {
  3909. NbtTrace(NBT_TRACE_INBOUND, ("Out of resource for %!ipaddr!:%d",
  3910. pIpAddress->Address[0].Address[0].in_addr, pIpAddress->Address[0].Address[0].sin_port));
  3911. return STATUS_INSUFFICIENT_RESOURCES;
  3912. }
  3913. pSessionReq->Hdr.Type = NBT_SESSION_REQUEST;
  3914. pSessionReq->Hdr.Flags = NBT_SESSION_FLAGS;
  3915. pSessionReq->Hdr.Length = (USHORT)htons(sLength- (USHORT)sizeof(tSESSIONHDR)); // size of called and calling NB names.
  3916. // put the Dest HalfAscii name into the Session Pdu
  3917. pCopyTo = ConvertToHalfAscii( (PCHAR)&pSessionReq->CalledName.NameLength,
  3918. pDeviceContext->MessageEndpoint,
  3919. NbtConfig.pScope,
  3920. NbtConfig.ScopeLength);
  3921. // put the Source HalfAscii name into the Session Pdu
  3922. pCopyTo = ConvertToHalfAscii(pCopyTo,
  3923. SourceName,
  3924. NbtConfig.pScope,
  3925. NbtConfig.ScopeLength);
  3926. // Inbound expects this lock to be held!
  3927. CTESpinLockAtDpc(pLowerConn);
  3928. status = Inbound(
  3929. NULL, // ReceiveEventContext - not used
  3930. pLowerConn, // ConnectionContext
  3931. 0, // ReceiveFlags - not used
  3932. sLength, // BytesIndicated
  3933. sLength, // BytesAvailable - not used
  3934. &BytesTaken, // BytesTaken
  3935. pSessionReq, // pTsdu
  3936. NULL // RcvBuffer
  3937. );
  3938. CTESpinFreeAtDpc(pLowerConn);
  3939. if (!NT_SUCCESS(status)) {
  3940. NbtTrace(NBT_TRACE_INBOUND, ("Inbound() returns %!status! for %!ipaddr!:%d %!NBTNAME!<%02x>",
  3941. status, pIpAddress->Address[0].Address[0].in_addr,
  3942. pIpAddress->Address[0].Address[0].sin_port, pCopyTo, (unsigned)pCopyTo[15]));
  3943. }
  3944. CTEMemFree( pSessionReq );
  3945. return status;
  3946. } // PerformInboundProcessing
  3947. #endif
  3948. //----------------------------------------------------------------------------
  3949. NTSTATUS
  3950. AcceptCompletionRoutine(
  3951. IN PDEVICE_OBJECT DeviceObject,
  3952. IN PIRP pIrp,
  3953. IN PVOID pContext
  3954. )
  3955. /*++
  3956. Routine Description:
  3957. This routine handles the completion of an Accept to the transport.
  3958. Arguments:
  3959. Return Value:
  3960. NTSTATUS - success or not
  3961. --*/
  3962. {
  3963. tLOWERCONNECTION *pLowerConn;
  3964. CTELockHandle OldIrq;
  3965. tDEVICECONTEXT *pDeviceContext;
  3966. pLowerConn = (tLOWERCONNECTION *)pContext;
  3967. pDeviceContext = pLowerConn->pDeviceContext;
  3968. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  3969. CTESpinLockAtDpc(pDeviceContext);
  3970. CTESpinLockAtDpc(pLowerConn);
  3971. //
  3972. // if the connection disconnects before the connect accept irp (this irp)
  3973. // completes do not put back on the free list here but let nbtdisconnect
  3974. // handle it.
  3975. // (i.e if the state is no longer INBOUND, then don't touch the connection
  3976. //
  3977. #ifdef _NETBIOSLESS
  3978. if (!NT_SUCCESS(pIrp->IoStatus.Status))
  3979. {
  3980. NbtTrace(NBT_TRACE_INBOUND, ("AcceptCompletionRoutine is called with %!status!", pIrp->IoStatus.Status));
  3981. if (pLowerConn->State == NBT_SESSION_INBOUND)
  3982. {
  3983. #else
  3984. if ((!NT_SUCCESS(pIrp->IoStatus.Status)) &&
  3985. (pLowerConn->State == NBT_SESSION_INBOUND))
  3986. {
  3987. #endif
  3988. //
  3989. // the accept failed, so close the connection and create
  3990. // a new one to be sure all activity is run down on the connection.
  3991. //
  3992. //
  3993. // Previously, the LowerConnection was in the SESSION_INBOUND state
  3994. // hence we have to remove it from the WaitingForInbound Q and put
  3995. // it on the active LowerConnection list!
  3996. //
  3997. RemoveEntryList (&pLowerConn->Linkage);
  3998. InsertTailList (&pLowerConn->pDeviceContext->LowerConnection, &pLowerConn->Linkage);
  3999. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  4000. //
  4001. // Change the RefCount Context to Connected!
  4002. //
  4003. NBT_SWAP_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, REF_LOWC_CONNECTED, TRUE);
  4004. InterlockedDecrement (&pLowerConn->pDeviceContext->NumWaitingForInbound);
  4005. CTESpinFreeAtDpc(pLowerConn);
  4006. CTESpinFreeAtDpc(pDeviceContext);
  4007. KdPrint(("Nbt.AcceptCompletionRoutine: error: %lx\n", pIrp->IoStatus.Status));
  4008. if (!NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT))
  4009. {
  4010. pDeviceContext = NULL;
  4011. }
  4012. CTEQueueForNonDispProcessing (DelayedCleanupAfterDisconnect,
  4013. NULL,
  4014. pLowerConn,
  4015. NULL,
  4016. pDeviceContext,
  4017. TRUE);
  4018. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4019. #ifdef _NETBIOSLESS
  4020. }
  4021. else if (pLowerConn->State == NBT_SESSION_UP)
  4022. {
  4023. NTSTATUS status;
  4024. // We are in message only mode and we need to clean up because the client rejected
  4025. // the accept for some reason. We are in the UP state so we need to do a heavy
  4026. // duty cleanup.
  4027. ASSERT( IsDeviceNetbiosless(pLowerConn->pDeviceContext) );
  4028. CTESpinFreeAtDpc(pLowerConn);
  4029. CTESpinFreeAtDpc(pDeviceContext);
  4030. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4031. KdPrint(("Nbt.AcceptCompletionRoutine: Message only error: %lx\n", pIrp->IoStatus.Status));
  4032. NbtTrace(NBT_TRACE_INBOUND, ("Message only error: %!status!", pIrp->IoStatus.Status));
  4033. // this call will indicate the disconnect to the client and clean up abit.
  4034. //
  4035. status = DisconnectHndlrNotOs (NULL,
  4036. (PVOID)pLowerConn,
  4037. 0,
  4038. NULL,
  4039. 0,
  4040. NULL,
  4041. TDI_DISCONNECT_ABORT);
  4042. }
  4043. else
  4044. {
  4045. // Already disconnected
  4046. CTESpinFreeAtDpc(pLowerConn);
  4047. CTESpinFreeAtDpc(pDeviceContext);
  4048. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4049. }
  4050. #endif
  4051. }
  4052. else
  4053. {
  4054. CTESpinFreeAtDpc(pLowerConn);
  4055. CTESpinFreeAtDpc(pDeviceContext);
  4056. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4057. }
  4058. // put the Irp back on its free list
  4059. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  4060. ExInterlockedInsertTailList (&NbtConfig.IrpFreeList,
  4061. &pIrp->Tail.Overlay.ListEntry,
  4062. &NbtConfig.LockInfo.SpinLock);
  4063. // return this status to stop the IO subsystem from further processing the
  4064. // IRP - i.e. trying to complete it back to the initiating thread! -since
  4065. // there is not initiating thread - we are the initiator
  4066. return(STATUS_MORE_PROCESSING_REQUIRED);
  4067. }
  4068. //----------------------------------------------------------------------------
  4069. NTSTATUS
  4070. TdiDisconnectHandler (
  4071. IN PVOID EventContext,
  4072. IN PVOID ConnectionContext,
  4073. IN ULONG DisconnectDataLength,
  4074. IN PVOID pDisconnectData,
  4075. IN ULONG DisconnectInformationLength,
  4076. IN PVOID pDisconnectInformation,
  4077. IN ULONG DisconnectIndicators
  4078. )
  4079. /*++
  4080. Routine Description:
  4081. This routine is called when a session is disconnected from a remote
  4082. machine.
  4083. Arguments:
  4084. IN PVOID EventContext,
  4085. IN PCONNECTION_CONTEXT ConnectionContext,
  4086. IN ULONG DisconnectDataLength,
  4087. IN PVOID DisconnectData,
  4088. IN ULONG DisconnectInformationLength,
  4089. IN PVOID DisconnectInformation,
  4090. IN ULONG DisconnectIndicators
  4091. Return Value:
  4092. NTSTATUS - Status of event indicator
  4093. --*/
  4094. {
  4095. NTSTATUS status;
  4096. tDEVICECONTEXT *pDeviceContext;
  4097. // convert the context value into the device context record ptr
  4098. pDeviceContext = (tDEVICECONTEXT *)EventContext;
  4099. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4100. KdPrint(("pDeviceContxt = %X ConnectEv = %X\n",pDeviceContext,ConnectionContext));
  4101. ASSERTMSG("Bad Device context passed to the Connection Event Handler",
  4102. pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
  4103. // call the non-OS specific routine to find a free connection.
  4104. status = DisconnectHndlrNotOs(
  4105. EventContext,
  4106. ConnectionContext,
  4107. DisconnectDataLength,
  4108. pDisconnectData,
  4109. DisconnectInformationLength,
  4110. pDisconnectInformation,
  4111. DisconnectIndicators);
  4112. if (!NT_SUCCESS(status))
  4113. {
  4114. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4115. KdPrint(("NO FREE CONNECTIONS in connect handler\n"));
  4116. return(STATUS_DATA_NOT_ACCEPTED);
  4117. }
  4118. return status;
  4119. }
  4120. //----------------------------------------------------------------------------
  4121. NTSTATUS
  4122. TdiRcvDatagramHandler(
  4123. IN PVOID pDgramEventContext,
  4124. IN int SourceAddressLength,
  4125. IN PVOID pSourceAddress,
  4126. IN int OptionsLength,
  4127. IN PVOID pOptions,
  4128. IN ULONG ReceiveDatagramFlags,
  4129. IN ULONG BytesIndicated,
  4130. IN ULONG BytesAvailable,
  4131. OUT ULONG *pBytesTaken,
  4132. IN PVOID pTsdu,
  4133. OUT PIRP *pIoRequestPacket
  4134. )
  4135. /*++
  4136. Routine Description:
  4137. This routine is the receive datagram event indication handler.
  4138. It is called when an Datagram arrives from the network, it will look for a
  4139. the address with an appropriate read datagram outstanding or a Datagrm
  4140. Event handler setup.
  4141. Arguments:
  4142. pDgramEventContext - Context provided for this event - pab
  4143. SourceAddressLength, - length of the src address
  4144. pSourceAddress, - src address
  4145. OptionsLength, - options length for the receive
  4146. pOptions, - options
  4147. BytesIndicated, - number of bytes this indication
  4148. BytesAvailable, - number of bytes in complete Tsdu
  4149. pTsdu - pointer to the datagram
  4150. Return Value:
  4151. *pBytesTaken - number of bytes used
  4152. *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
  4153. NTSTATUS - Status of receive operation
  4154. --*/
  4155. {
  4156. NTSTATUS status;
  4157. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
  4158. tDGRAMHDR UNALIGNED *pDgram = (tDGRAMHDR UNALIGNED *)pTsdu;
  4159. PIRP pIrp = NULL;
  4160. ULONG lBytesTaken;
  4161. tCLIENTLIST *pClientList;
  4162. CTELockHandle OldIrq;
  4163. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4164. KdPrint(( "NBT receive datagram handler pDeviceContext: %X\n",
  4165. pDeviceContext ));
  4166. *pIoRequestPacket = NULL;
  4167. ASSERTMSG("NBT:Invalid Device Context passed to DgramRcv Handler!!\n",
  4168. pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
  4169. // call a non-OS specific routine to decide what to do with the datagrams
  4170. pIrp = NULL;
  4171. pClientList = NULL;
  4172. status = DgramHndlrNotOs(
  4173. pDgramEventContext,
  4174. SourceAddressLength,
  4175. pSourceAddress,
  4176. OptionsLength,
  4177. pOptions,
  4178. ReceiveDatagramFlags,
  4179. BytesIndicated,
  4180. BytesAvailable,
  4181. &lBytesTaken,
  4182. pTsdu,
  4183. (PVOID *)&pIrp,
  4184. &pClientList);
  4185. if ( !NT_SUCCESS(status) )
  4186. {
  4187. // fail the request back to the transport provider since we
  4188. // could not find a receive buffer or receive handler or the
  4189. // data was taken in the indication handler.
  4190. //
  4191. return(STATUS_DATA_NOT_ACCEPTED);
  4192. }
  4193. else
  4194. {
  4195. // a rcv buffer was returned, so use it for the receive.(an Irp)
  4196. PTDI_REQUEST_KERNEL_RECEIVEDG pParams;
  4197. PIO_STACK_LOCATION pIrpSp;
  4198. ULONG lRcvLength;
  4199. ULONG lRcvFlags;
  4200. // When the client list is returned, we need to make up an irp to
  4201. // send down to the transport, which we will use in the completion
  4202. // routine to copy the data to all clients, ONLY if we are not
  4203. // using a client buffer, so check that flag first.
  4204. //
  4205. if (pClientList && !pClientList->fUsingClientBuffer)
  4206. {
  4207. PMDL pMdl;
  4208. PVOID pBuffer;
  4209. //
  4210. // get an irp to do the receive with and attach
  4211. // a buffer to it.
  4212. //
  4213. while (1)
  4214. {
  4215. if (NT_SUCCESS(GetIrp(&pIrp)))
  4216. {
  4217. if (pBuffer = NbtAllocMem (BytesAvailable, NBT_TAG('t')))
  4218. {
  4219. if (pMdl = IoAllocateMdl (pBuffer, BytesAvailable, FALSE, FALSE, NULL))
  4220. {
  4221. break;
  4222. }
  4223. KdPrint(("Nbt.TdiRcvDatagramHandler: Unable to IoAllocateMdl, Kill Connection\n"));
  4224. CTEMemFree(pBuffer);
  4225. }
  4226. else
  4227. {
  4228. KdPrint(("Nbt.TdiRcvDatagramHandler: Unable to allocate Buffer, Kill Connection\n"));
  4229. }
  4230. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  4231. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  4232. &pIrp->Tail.Overlay.ListEntry,
  4233. &NbtConfig.LockInfo.SpinLock);
  4234. }
  4235. else
  4236. {
  4237. KdPrint(("Nbt.TdiRcvDatagramHandler: Unable to GetIrp, Kill Connection\n"));
  4238. }
  4239. if (!pClientList->fProxy)
  4240. {
  4241. //
  4242. // We failed, so Dereference the Client + Address we had
  4243. // reference earlier for multiple clients
  4244. //
  4245. NBT_DEREFERENCE_CLIENT (pClientList->pClientEle);
  4246. NBT_DEREFERENCE_ADDRESS (pClientList->pAddress, REF_ADDR_MULTICLIENTS);
  4247. CTEMemFree(pClientList->pRemoteAddress);
  4248. }
  4249. CTEMemFree(pClientList);
  4250. return (STATUS_DATA_NOT_ACCEPTED);
  4251. }
  4252. // Map the pages in memory...
  4253. MmBuildMdlForNonPagedPool(pMdl);
  4254. pIrp->MdlAddress = pMdl;
  4255. lRcvFlags = 0;
  4256. lRcvLength = BytesAvailable;
  4257. }
  4258. else
  4259. {
  4260. ASSERT(pIrp);
  4261. // *TODO* may have to keep track of the case where the
  4262. // client returns a buffer that is not large enough for all of the
  4263. // data indicated. So the next posting of a buffer gets passed
  4264. // directly to the transport.
  4265. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4266. lRcvFlags = ((PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters)->ReceiveFlags;
  4267. lRcvLength = ((PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters)->ReceiveLength;
  4268. if (lRcvLength < BytesIndicated - lBytesTaken)
  4269. {
  4270. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4271. KdPrint(("Nbt:Clients Buffer is too short on Rcv Dgram size= %X, needed = %X\n",
  4272. lRcvLength, BytesIndicated-lBytesTaken));
  4273. }
  4274. }
  4275. // this code is sped up somewhat by expanding the code here rather than calling
  4276. // the TdiBuildReceive macro
  4277. // make the next stack location the current one. Normally IoCallDriver
  4278. // would do this but we are not going through IoCallDriver here, since the
  4279. // Irp is just passed back with RcvIndication.
  4280. ASSERT(pIrp->CurrentLocation > 1);
  4281. IoSetNextIrpStackLocation(pIrp);
  4282. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4283. pIrpSp->CompletionRoutine = CompletionRcvDgram;
  4284. // pass the ClientList to the completion routine so it can
  4285. // copy the datagram to several clients that may be listening on the
  4286. // same name
  4287. //
  4288. pIrpSp->Context = (PVOID)pClientList;
  4289. CHECK_PTR(pIrpSp);
  4290. pIrpSp->Flags = 0;
  4291. // set flags so the completion routine is always invoked.
  4292. pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
  4293. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  4294. pIrpSp->MinorFunction = TDI_RECEIVE_DATAGRAM;
  4295. //
  4296. // Verify that we have a valid Device and FileObject for TcpIp below
  4297. //
  4298. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4299. if (pDeviceContext->pFileObjects)
  4300. {
  4301. pIrpSp->DeviceObject = pDeviceContext->pFileObjects->pDgramDeviceObject;
  4302. pIrpSp->FileObject = pDeviceContext->pFileObjects->pDgramFileObject;
  4303. }
  4304. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4305. pParams = (PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters;
  4306. pParams->ReceiveFlags = lRcvFlags;
  4307. pParams->ReceiveLength = lRcvLength;
  4308. // pass back the irp to the transport provider and increment the stack
  4309. // location so it can write to the irp if it needs to.
  4310. *pIoRequestPacket = pIrp;
  4311. *pBytesTaken = lBytesTaken;
  4312. return(STATUS_MORE_PROCESSING_REQUIRED);
  4313. }
  4314. //
  4315. // Transport will complete the processing of the request, we don't
  4316. // want the datagram.
  4317. //
  4318. IF_DBG (NBT_DEBUG_TDIHNDLR)
  4319. KdPrint(( "NBT receive datagram handler ignored receive, pDeviceContext: %X\n",
  4320. pDeviceContext ));
  4321. return STATUS_DATA_NOT_ACCEPTED;
  4322. // to keep the compiler from generating warnings...
  4323. UNREFERENCED_PARAMETER( SourceAddressLength );
  4324. UNREFERENCED_PARAMETER( BytesIndicated );
  4325. UNREFERENCED_PARAMETER( BytesAvailable );
  4326. UNREFERENCED_PARAMETER( pBytesTaken );
  4327. UNREFERENCED_PARAMETER( pTsdu );
  4328. UNREFERENCED_PARAMETER( OptionsLength );
  4329. UNREFERENCED_PARAMETER( pOptions );
  4330. }
  4331. //----------------------------------------------------------------------------
  4332. NTSTATUS
  4333. TdiRcvNameSrvHandler(
  4334. IN PVOID pDgramEventContext,
  4335. IN int SourceAddressLength,
  4336. IN PVOID pSourceAddress,
  4337. IN int OptionsLength,
  4338. IN PVOID pOptions,
  4339. IN ULONG ReceiveDatagramFlags,
  4340. IN ULONG BytesIndicated,
  4341. IN ULONG BytesAvailable,
  4342. OUT ULONG *pBytesTaken,
  4343. IN PVOID pTsdu,
  4344. OUT PIRP *pIoRequestPacket
  4345. )
  4346. /*++
  4347. Routine Description:
  4348. This routine is the Name Service datagram event indication handler.
  4349. It gets all datagrams destined for UDP port 137
  4350. Arguments:
  4351. pDgramEventContext - Context provided for this event - pab
  4352. SourceAddressLength, - length of the src address
  4353. pSourceAddress, - src address
  4354. OptionsLength, - options length for the receive
  4355. pOptions, - options
  4356. BytesIndicated, - number of bytes this indication
  4357. BytesAvailable, - number of bytes in complete Tsdu
  4358. pTsdu - pointer to the datagram
  4359. Return Value:
  4360. *pBytesTaken - number of bytes used
  4361. *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
  4362. NTSTATUS - Status of receive operation
  4363. --*/
  4364. {
  4365. NTSTATUS status;
  4366. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
  4367. tNAMEHDR UNALIGNED *pNameSrv = (tNAMEHDR UNALIGNED *)pTsdu;
  4368. USHORT OpCode;
  4369. IF_DBG(NBT_DEBUG_TDIHNDLR)
  4370. KdPrint(( "NBT: NAMEHDR datagram handler pDeviceContext: %X\n",
  4371. pDeviceContext ));
  4372. *pIoRequestPacket = NULL;
  4373. //
  4374. // check if the whole datagram has arrived yet
  4375. //
  4376. if (BytesIndicated != BytesAvailable)
  4377. {
  4378. PIRP pIrp;
  4379. PVOID pBuffer;
  4380. PMDL pMdl;
  4381. ULONG Length;
  4382. //
  4383. // get an irp to do the receive with and attach
  4384. // a buffer to it.
  4385. //
  4386. status = GetIrp(&pIrp);
  4387. if (!NT_SUCCESS(status))
  4388. {
  4389. return(STATUS_DATA_NOT_ACCEPTED);
  4390. }
  4391. //
  4392. // make an Mdl for a buffer to get all of the data from
  4393. // the transprot
  4394. //
  4395. Length = BytesAvailable + SourceAddressLength + sizeof(ULONG);
  4396. Length = ((Length + 3)/sizeof(ULONG)) * sizeof(ULONG);
  4397. pBuffer = NbtAllocMem(Length,NBT_TAG('u'));
  4398. if (pBuffer)
  4399. {
  4400. PVOID pSrcAddr;
  4401. //
  4402. // save the source address and length in the buffer for later
  4403. // indication back to this routine.
  4404. //
  4405. *(ULONG UNALIGNED *)((PUCHAR)pBuffer + BytesAvailable) = SourceAddressLength;
  4406. pSrcAddr = (PVOID)((PUCHAR)pBuffer + BytesAvailable + sizeof(ULONG));
  4407. CTEMemCopy(pSrcAddr,
  4408. pSourceAddress,
  4409. SourceAddressLength);
  4410. // Allocate a MDL and set the header sizes correctly
  4411. pMdl = IoAllocateMdl(
  4412. pBuffer,
  4413. BytesAvailable,
  4414. FALSE,
  4415. FALSE,
  4416. NULL);
  4417. if (pMdl)
  4418. {
  4419. // Map the pages in memory...
  4420. MmBuildMdlForNonPagedPool(pMdl);
  4421. pIrp->MdlAddress = pMdl;
  4422. ASSERT(pDeviceContext);
  4423. //
  4424. // Build a Datagram Receive Irp (as opposed to a Connect Receive Irp)
  4425. // Bug# 125816
  4426. //
  4427. TdiBuildReceiveDatagram(
  4428. pIrp,
  4429. &pDeviceContext->DeviceObject,
  4430. pDeviceContext->pFileObjects->pNameServerFileObject,
  4431. NameSrvCompletionRoutine,
  4432. ULongToPtr(BytesAvailable),
  4433. pMdl,
  4434. BytesAvailable,
  4435. NULL,
  4436. NULL,
  4437. (ULONG)TDI_RECEIVE_NORMAL);
  4438. *pBytesTaken = 0;
  4439. *pIoRequestPacket = pIrp;
  4440. // make the next stack location the current one. Normally IoCallDriver
  4441. // would do this but we are not going through IoCallDriver here, since the
  4442. // Irp is just passed back with RcvIndication.
  4443. //
  4444. ASSERT(pIrp->CurrentLocation > 1);
  4445. IoSetNextIrpStackLocation(pIrp);
  4446. return(STATUS_MORE_PROCESSING_REQUIRED);
  4447. }
  4448. CTEMemFree(pBuffer);
  4449. }
  4450. // put our Irp back on its free list
  4451. //
  4452. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  4453. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  4454. &pIrp->Tail.Overlay.ListEntry,
  4455. &NbtConfig.LockInfo.SpinLock);
  4456. return(STATUS_DATA_NOT_ACCEPTED);
  4457. }
  4458. //
  4459. // Bug# 125279: Ensure that we have received enough data to be able to
  4460. // read most data fields
  4461. if (BytesIndicated < NBT_MINIMUM_QUERY) // should this be limited to 12 ?
  4462. {
  4463. KdPrint (("Nbt.TdiRcvNameSrvHandler: WARNING!!! Rejecting Request -- BytesIndicated=<%d> < <%d>\n",
  4464. BytesIndicated, NBT_MINIMUM_QUERY));
  4465. return(STATUS_DATA_NOT_ACCEPTED);
  4466. }
  4467. if (pWinsInfo)
  4468. {
  4469. USHORT TransactionId;
  4470. ULONG SrcAddress;
  4471. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&((PTRANSPORT_ADDRESS)pSourceAddress)->Address[0].Address[0])->in_addr);
  4472. //
  4473. // Pass To Wins if:
  4474. //
  4475. // 1) It is a response pdu with the transaction id in the WINS range
  4476. // that is not a WACK... OR
  4477. // 2) It is a request that is NOT broadcast....and...
  4478. // 2) It is a name query(excluding node status requests),
  4479. // Allowing queries from other netbt clients
  4480. // allowing queries from anyone not on this machine OR
  4481. // 3) It is a name release request. OR
  4482. // 4) It is a name refresh OR
  4483. // 5) It is a name registration
  4484. //
  4485. OpCode = pNameSrv->OpCodeFlags;
  4486. TransactionId = ntohs(pNameSrv->TransactId);
  4487. if (((OpCode & OP_RESPONSE) && (TransactionId <= WINS_MAXIMUM_TRANSACTION_ID) && (OpCode != OP_WACK))
  4488. ||
  4489. ((!(OpCode & (OP_RESPONSE | FL_BROADCAST)))
  4490. &&
  4491. ((((OpCode & NM_FLAGS_MASK) == OP_QUERY) &&
  4492. (OpCode & FL_RECURDESIRE) && // not node status request
  4493. ((TransactionId > WINS_MAXIMUM_TRANSACTION_ID) || (!SrcIsUs(SrcAddress))))
  4494. ||
  4495. (OpCode & (OP_RELEASE | OP_REFRESH))
  4496. ||
  4497. (OpCode & OP_REGISTRATION))))
  4498. {
  4499. status = PassNamePduToWins(
  4500. pDeviceContext,
  4501. pSourceAddress,
  4502. pNameSrv,
  4503. BytesIndicated);
  4504. // NbtConfig.DgramBytesRcvd += BytesIndicated;
  4505. //
  4506. // if WINS took the data then tell the transport to dump the data
  4507. // since we have buffered it already. Otherwise, let nbt take
  4508. // a look at the data
  4509. //
  4510. if (NT_SUCCESS(status))
  4511. {
  4512. return(STATUS_DATA_NOT_ACCEPTED);
  4513. }
  4514. }
  4515. }
  4516. // DO a quick check of the name to see if it is in the local name table
  4517. // and reject it otherwise - for name queries only, if not the proxy
  4518. //
  4519. if (!(NodeType & PROXY))
  4520. {
  4521. ULONG UNALIGNED *pHdr;
  4522. ULONG i,lValue;
  4523. UCHAR pNameStore[NETBIOS_NAME_SIZE];
  4524. UCHAR *pName;
  4525. tNAMEADDR *pNameAddr;
  4526. CTELockHandle OldIrq;
  4527. // it must be a name query request, not a response, and not a
  4528. // node status request, to enter this special check
  4529. //
  4530. OpCode = pNameSrv->OpCodeFlags;
  4531. if (((OpCode & NM_FLAGS_MASK) == OP_QUERY) &&
  4532. (!(OpCode & OP_RESPONSE)) &&
  4533. (OpCode & FL_RECURDESIRE)) // not node status request
  4534. {
  4535. pHdr = (ULONG UNALIGNED *)pNameSrv->NameRR.NetBiosName;
  4536. pName = pNameStore;
  4537. // the Half Ascii portion of the netbios name is always 32 bytes long
  4538. for (i=0; i < NETBIOS_NAME_SIZE*2 ;i +=4 )
  4539. {
  4540. lValue = *pHdr - 0x41414141; // four A's
  4541. pHdr++;
  4542. lValue = ((lValue & 0x0F000000) >> 16) +
  4543. ((lValue & 0x0F0000) >> 4) +
  4544. ((lValue & 0x0F00) >> 8) +
  4545. ((lValue & 0x0F) << 4);
  4546. *(PUSHORT)pName = (USHORT)lValue;
  4547. ((PUSHORT)pName)++;
  4548. }
  4549. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4550. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  4551. pNameStore,
  4552. NULL,
  4553. &pNameAddr);
  4554. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4555. if (!NT_SUCCESS(status))
  4556. {
  4557. *pBytesTaken = BytesIndicated;
  4558. return(STATUS_DATA_NOT_ACCEPTED);
  4559. }
  4560. }
  4561. }
  4562. ASSERT(pDeviceContext);
  4563. // call a non-OS specific routine to decide what to do with the datagrams
  4564. status = NameSrvHndlrNotOs(
  4565. pDeviceContext,
  4566. pSourceAddress,
  4567. pNameSrv,
  4568. BytesIndicated,
  4569. (BOOLEAN)((ReceiveDatagramFlags & TDI_RECEIVE_BROADCAST) != 0));
  4570. // NbtConfig.DgramBytesRcvd += BytesIndicated
  4571. return status;
  4572. // to keep the compiler from generating warnings...
  4573. UNREFERENCED_PARAMETER( SourceAddressLength );
  4574. UNREFERENCED_PARAMETER( BytesIndicated );
  4575. UNREFERENCED_PARAMETER( BytesAvailable );
  4576. UNREFERENCED_PARAMETER( pBytesTaken );
  4577. UNREFERENCED_PARAMETER( pTsdu );
  4578. UNREFERENCED_PARAMETER( OptionsLength );
  4579. UNREFERENCED_PARAMETER( pOptions );
  4580. }
  4581. //----------------------------------------------------------------------------
  4582. NTSTATUS
  4583. NameSrvCompletionRoutine(
  4584. IN PDEVICE_OBJECT DeviceObject,
  4585. IN PIRP pIrp,
  4586. IN PVOID Context
  4587. )
  4588. /*++
  4589. Routine Description:
  4590. This routine handles the case when a name service datagram is too
  4591. short and and Irp has to be passed back to the transport to get the
  4592. rest of the datagram. The irp completes through here when full.
  4593. Arguments:
  4594. DeviceObject - unused.
  4595. Irp - Supplies Irp that the transport has finished processing.
  4596. Context - Supplies the pConnectEle - the connection data structure
  4597. Return Value:
  4598. The final status from the operation (success or an exception).
  4599. --*/
  4600. {
  4601. NTSTATUS status;
  4602. PIRP pIoRequestPacket;
  4603. ULONG BytesTaken;
  4604. ULONG Offset = PtrToUlong(Context);
  4605. PVOID pBuffer;
  4606. ULONG SrcAddressLength;
  4607. PVOID pSrcAddress;
  4608. IF_DBG (NBT_DEBUG_TDIHNDLR)
  4609. KdPrint(("NameSrvCompletionRoutine pRcvBuffer: %X, Status: %X Length %X\n",
  4610. Context, pIrp->IoStatus.Status, pIrp->IoStatus.Information));
  4611. if (pBuffer = MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority))
  4612. {
  4613. SrcAddressLength = *(ULONG UNALIGNED *)((PUCHAR)pBuffer + Offset);
  4614. pSrcAddress = (PVOID)((PUCHAR)pBuffer + Offset + sizeof(ULONG));
  4615. if (!DeviceObject)
  4616. {
  4617. DeviceObject = (IoGetNextIrpStackLocation (pIrp))->DeviceObject;
  4618. }
  4619. //
  4620. // just call the regular indication routine as if UDP had done it.
  4621. //
  4622. TdiRcvNameSrvHandler (DeviceObject,
  4623. SrcAddressLength,
  4624. pSrcAddress,
  4625. 0,
  4626. NULL,
  4627. TDI_RECEIVE_NORMAL,
  4628. (ULONG) pIrp->IoStatus.Information,
  4629. (ULONG) pIrp->IoStatus.Information,
  4630. &BytesTaken,
  4631. pBuffer,
  4632. &pIoRequestPacket);
  4633. CTEMemFree (pBuffer);
  4634. }
  4635. //
  4636. // put our Irp back on its free list
  4637. //
  4638. IoFreeMdl (pIrp->MdlAddress);
  4639. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  4640. ExInterlockedInsertTailList (&NbtConfig.IrpFreeList,
  4641. &pIrp->Tail.Overlay.ListEntry,
  4642. &NbtConfig.LockInfo.SpinLock);
  4643. return (STATUS_MORE_PROCESSING_REQUIRED);
  4644. }
  4645. //----------------------------------------------------------------------------
  4646. NTSTATUS
  4647. CompletionRcvDgram(
  4648. IN PDEVICE_OBJECT DeviceObject,
  4649. IN PIRP Irp,
  4650. IN PVOID Context
  4651. )
  4652. /*++
  4653. Routine Description:
  4654. This routine completes the Irp by removing the Rcv Element off the queue
  4655. and putting it back on the free list.
  4656. Arguments:
  4657. DeviceObject - unused.
  4658. Irp - Supplies Irp that the transport has finished processing.
  4659. Context - Supplies the pConnectEle - the connection data structure
  4660. Return Value:
  4661. The final status from the operation (success or an exception).
  4662. --*/
  4663. {
  4664. NTSTATUS status;
  4665. PLIST_ENTRY pHead;
  4666. PLIST_ENTRY pEntry;
  4667. PTA_NETBIOS_ADDRESS pRemoteAddress;
  4668. ULONG RemoteAddressLength;
  4669. ULONG BytesCopied;
  4670. PVOID pTsdu;
  4671. ULONG ReceiveFlags;
  4672. tCLIENTLIST *pClientList;
  4673. CTELockHandle OldIrq;
  4674. CTELockHandle OldIrq1;
  4675. ULONG ClientBytesTaken;
  4676. ULONG DataLength;
  4677. tADDRESSELE *pAddress;
  4678. tRCVELE *pRcvEle;
  4679. PLIST_ENTRY pRcvEntry;
  4680. tDEVICECONTEXT *pDeviceContext;
  4681. CTEULONGLONG AdapterMask;
  4682. IF_DBG (NBT_DEBUG_TDIHNDLR)
  4683. KdPrint(("CompletionRcvDgram pRcvBuffer: %X, Status: %X Length %X\n",
  4684. Context,
  4685. Irp->IoStatus.Status,
  4686. Irp->IoStatus.Information ));
  4687. // there may be several clients that want to see this datagram so check
  4688. // the client list to see...
  4689. //
  4690. if (Context)
  4691. {
  4692. tCLIENTELE *pClientPrev = NULL;
  4693. //
  4694. // Bug# 124683: Data may be invalid if Completion status was failure
  4695. //
  4696. if (NT_SUCCESS (Irp->IoStatus.Status))
  4697. {
  4698. DataLength = (ULONG)Irp->IoStatus.Information;
  4699. }
  4700. else
  4701. {
  4702. ASSERT (0);
  4703. DataLength = 0;
  4704. }
  4705. pTsdu = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, HighPagePriority);
  4706. pClientList = (tCLIENTLIST *) Context;
  4707. #ifdef PROXY_NODE
  4708. if (pClientList->fProxy)
  4709. {
  4710. //
  4711. // Call the ProxyDoDgramDist
  4712. //
  4713. status = ProxyDoDgramDist( pTsdu, DataLength,
  4714. (tNAMEADDR *)pClientList->pAddress, //NameAddr
  4715. pClientList->pRemoteAddress); //device context
  4716. }
  4717. else
  4718. #endif
  4719. {
  4720. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4721. // for the multihomed host, we only want to distribute the inbound
  4722. // datagram to clients on this same adapter, to avoid giving the
  4723. // datagram to the same client several times, once for each adapter
  4724. // it is bound to.
  4725. //
  4726. pDeviceContext = pClientList->pClientEle->pDeviceContext;
  4727. AdapterMask = pDeviceContext->AdapterMask;
  4728. pAddress = pClientList->pAddress;
  4729. pRemoteAddress = pClientList->pRemoteAddress;
  4730. RemoteAddressLength = pClientList->RemoteAddressLength;
  4731. ReceiveFlags = pClientList->ReceiveDatagramFlags;
  4732. //
  4733. // Since we will be traversing the ClientHead, lock
  4734. // the Address (we have already referenced the Address
  4735. // + Client in DgramRcvNotOs)
  4736. //
  4737. CTESpinLock(pAddress, OldIrq1);
  4738. pHead = &pClientList->pAddress->ClientHead;
  4739. pEntry = pHead->Flink;
  4740. if (!pClientList->fUsingClientBuffer)
  4741. {
  4742. while (pEntry != pHead)
  4743. {
  4744. PTDI_IND_RECEIVE_DATAGRAM EvRcvDgram;
  4745. PVOID RcvDgramEvContext;
  4746. tCLIENTELE *pClientEle;
  4747. PIRP pRcvIrp;
  4748. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  4749. // for multihomed hosts only distribute the datagram to
  4750. // clients hooked to this device context to avoid duplicate
  4751. // indications
  4752. //
  4753. if ((pClientEle->Verify == NBT_VERIFY_CLIENT) && // as opposed to CLIENT_DOWN!
  4754. (pClientEle->pDeviceContext->AdapterMask == AdapterMask))
  4755. {
  4756. EvRcvDgram = pClientEle->evRcvDgram;
  4757. RcvDgramEvContext = pClientEle->RcvDgramEvContext;
  4758. RemoteAddressLength = FIELD_OFFSET(TA_NETBIOS_ADDRESS,
  4759. Address[0].Address[0].NetbiosName[NETBIOS_NAME_SIZE]);
  4760. //
  4761. // Bug # 452211 -- since one of the clients may have the Extended
  4762. // addressing field set, set the # of addresses accordingly
  4763. //
  4764. if (pClientEle->ExtendedAddress)
  4765. {
  4766. pRemoteAddress->TAAddressCount = 2;
  4767. RemoteAddressLength += FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP);
  4768. }
  4769. else
  4770. {
  4771. pRemoteAddress->TAAddressCount = 1;
  4772. }
  4773. NBT_REFERENCE_CLIENT(pClientEle);
  4774. CTESpinFree(pAddress, OldIrq1);
  4775. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  4776. // dereference the previous client in the list
  4777. if (pClientPrev)
  4778. {
  4779. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4780. }
  4781. pClientPrev = pClientEle;
  4782. pRcvIrp = NULL;
  4783. ClientBytesTaken = 0;
  4784. status = (*EvRcvDgram) (RcvDgramEvContext,
  4785. RemoteAddressLength,
  4786. pRemoteAddress,
  4787. 0,
  4788. NULL,
  4789. #ifndef VXD
  4790. ReceiveFlags,
  4791. #endif
  4792. DataLength,
  4793. DataLength,
  4794. &ClientBytesTaken,
  4795. pTsdu,
  4796. &pRcvIrp);
  4797. if (!pRcvIrp)
  4798. {
  4799. // if no buffer is returned, then the client is done
  4800. // with the data so go to the next client ...since it may
  4801. // be possible to process all clients in this loop without
  4802. // ever sending an irp down to the transport
  4803. // free the remote address mem block
  4804. status = STATUS_DATA_NOT_ACCEPTED;
  4805. }
  4806. else
  4807. {
  4808. // the client has passed back an irp so
  4809. // copy the data to the client's Irp
  4810. //
  4811. TdiCopyBufferToMdl(pTsdu,
  4812. ClientBytesTaken,
  4813. DataLength - ClientBytesTaken,
  4814. pRcvIrp->MdlAddress,
  4815. 0,
  4816. &BytesCopied);
  4817. // length is copied length (since the MDL may be
  4818. // too short to take it all)
  4819. //
  4820. if (BytesCopied < (DataLength-ClientBytesTaken))
  4821. {
  4822. pRcvIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  4823. }
  4824. else
  4825. {
  4826. pRcvIrp->IoStatus.Status = STATUS_SUCCESS;
  4827. }
  4828. pRcvIrp->IoStatus.Information = BytesCopied;
  4829. IoCompleteRequest(pRcvIrp,IO_NETWORK_INCREMENT);
  4830. }
  4831. CTESpinLock(&NbtConfig.JointLock, OldIrq);
  4832. CTESpinLock(pAddress, OldIrq1);
  4833. }
  4834. // this code is protected from a client removing itself
  4835. // from the list of clients attached to an address by
  4836. // referencing the client prior to releasing the spin lock
  4837. // on the address. The client element does not get
  4838. // removed from the address list until its ref count goes
  4839. // to zero. We must hold the joint spin lock to prevent the
  4840. // next client from deleting itself from the list before we
  4841. // can increment its reference count.
  4842. //
  4843. pEntry = pEntry->Flink;
  4844. } // of while(pEntry != pHead)
  4845. }
  4846. else
  4847. {
  4848. // *** Client Has posted a receive Buffer, rather than using
  4849. // *** receive handler - VXD case!
  4850. // ***
  4851. while (pEntry != pHead)
  4852. {
  4853. tCLIENTELE *pClientEle;
  4854. PIRP pRcvIrp;
  4855. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  4856. // for multihomed hosts only distribute the datagram to
  4857. // clients hooked to this device context to avoid duplicate
  4858. // indications
  4859. //
  4860. if (pClientEle->pDeviceContext->AdapterMask == AdapterMask)
  4861. {
  4862. if (pClientEle == pClientList->pClientEle)
  4863. {
  4864. // this is the client whose buffer we are using - it is
  4865. // passed up to the client after all other clients
  4866. // have been processed.
  4867. //
  4868. pEntry = pEntry->Flink;
  4869. continue;
  4870. }
  4871. // check for datagrams posted to this name
  4872. //
  4873. if (!IsListEmpty(&pClientEle->RcvDgramHead))
  4874. {
  4875. pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
  4876. pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
  4877. pRcvIrp = pRcvEle->pIrp;
  4878. //
  4879. // copy the data to the client's Irp
  4880. //
  4881. TdiCopyBufferToMdl(pTsdu,
  4882. 0,
  4883. DataLength,
  4884. pRcvIrp->MdlAddress,
  4885. 0,
  4886. &BytesCopied);
  4887. // length is copied length (since the MDL may be too short to take it all)
  4888. if (BytesCopied < DataLength)
  4889. {
  4890. pRcvIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  4891. }
  4892. else
  4893. {
  4894. pRcvIrp->IoStatus.Status = STATUS_SUCCESS;
  4895. }
  4896. pRcvIrp->IoStatus.Information = BytesCopied;
  4897. //
  4898. // Increment the RefCount so that this Client hangs around!
  4899. //
  4900. NBT_REFERENCE_CLIENT (pClientEle);
  4901. CTESpinFree(pAddress, OldIrq1);
  4902. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  4903. //
  4904. // undo the InterlockedIncrement to the Previous client
  4905. //
  4906. if (pClientPrev)
  4907. {
  4908. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4909. }
  4910. pClientPrev = pClientEle;
  4911. IoCompleteRequest(pRcvIrp,IO_NETWORK_INCREMENT);
  4912. // free the receive block
  4913. CTEMemFree((PVOID)pRcvEle);
  4914. CTESpinLock(&NbtConfig.JointLock, OldIrq);
  4915. CTESpinLock(pAddress, OldIrq1);
  4916. }
  4917. pEntry = pEntry->Flink;
  4918. }
  4919. } // of while(pEntry != pHead)
  4920. CTESpinFree(pAddress, OldIrq1);
  4921. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  4922. // undo the InterlockedIncrement on the refcount
  4923. if (pClientPrev)
  4924. {
  4925. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4926. }
  4927. //
  4928. // The Client + Address were referenced in DgramRcvNotOs to be sure they did not
  4929. // disappear until this dgram rcv was done, which is now.
  4930. //
  4931. NBT_DEREFERENCE_CLIENT (pClientList->pClientEle); // Bug#: 124675
  4932. NBT_DEREFERENCE_ADDRESS (pClientList->pAddress, REF_ADDR_MULTICLIENTS);
  4933. // free the remote address structure and the client list
  4934. // allocated in DgramHndlrNotOs
  4935. //
  4936. CTEMemFree (pClientList->pRemoteAddress);
  4937. CTEMemFree (pClientList);
  4938. // returning success allows the IO subsystem to complete the
  4939. // irp that we used to get the data - i.e. one client's
  4940. // buffer
  4941. //
  4942. return(STATUS_SUCCESS);
  4943. }
  4944. CTESpinFree(pAddress, OldIrq1);
  4945. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4946. // dereference the previous client in the list from the RcvHANDLER
  4947. // case a page or so above...
  4948. //
  4949. if (pClientPrev)
  4950. {
  4951. NBT_DEREFERENCE_CLIENT(pClientPrev);
  4952. }
  4953. //
  4954. // The Client + Address were referenced in DgramRcvNotOs to be sure they did not
  4955. // disappear until this dgram rcv was done, which is now.
  4956. //
  4957. NBT_DEREFERENCE_CLIENT (pClientList->pClientEle); // Bug#: 124675
  4958. NBT_DEREFERENCE_ADDRESS (pClientList->pAddress, REF_ADDR_MULTICLIENTS);
  4959. }
  4960. //
  4961. // Free the buffers allocated
  4962. //
  4963. if (!pClientList->fProxy)
  4964. {
  4965. CTEMemFree (pClientList->pRemoteAddress);
  4966. }
  4967. CTEMemFree (pClientList);
  4968. CTEMemFree(pTsdu);
  4969. //
  4970. // Free the Mdl + put the Irp back on its free list
  4971. //
  4972. IF_DBG(NBT_DEBUG_RCV)
  4973. KdPrint(("****Freeing Mdl: Irp = %X Mdl = %X\n",Irp,Irp->MdlAddress));
  4974. IoFreeMdl(Irp->MdlAddress);
  4975. REMOVE_FROM_LIST(&Irp->ThreadListEntry);
  4976. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  4977. &Irp->Tail.Overlay.ListEntry,
  4978. &NbtConfig.LockInfo.SpinLock);
  4979. return(STATUS_MORE_PROCESSING_REQUIRED);
  4980. }
  4981. // for the single receive case this passes the rcv up to the client
  4982. //
  4983. return(STATUS_SUCCESS);
  4984. UNREFERENCED_PARAMETER( DeviceObject );
  4985. }
  4986. //----------------------------------------------------------------------------
  4987. NTSTATUS
  4988. TdiErrorHandler (
  4989. IN PVOID Context,
  4990. IN NTSTATUS Status
  4991. )
  4992. /*++
  4993. Routine Description:
  4994. This routine is called on any error indications passed back from the
  4995. transport. It implements LAN_STATUS_ALERT.
  4996. Arguments:
  4997. Context - Supplies the pfcb for the address.
  4998. Status - Supplies the error.
  4999. Return Value:
  5000. NTSTATUS - Status of event indication
  5001. --*/
  5002. {
  5003. #ifdef _NETBIOSLESS
  5004. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)Context;
  5005. // If NB-full trys to contact NB-less host, we may get this error
  5006. if ( (Status == STATUS_PORT_UNREACHABLE) ||
  5007. (Status == STATUS_HOST_UNREACHABLE))
  5008. {
  5009. return(STATUS_DATA_NOT_ACCEPTED);
  5010. }
  5011. // TODO: Log a message here
  5012. KdPrint(("Nbt.TdiErrorHandler: TDI error event notification\n\tDevice %x\n\tStatus: 0x%x\n",
  5013. pDeviceContext, Status));
  5014. #else
  5015. KdPrint(("Nbt.TdiErrorHandler: Error Event HAndler hit unexpectedly\n"));
  5016. #endif
  5017. return(STATUS_DATA_NOT_ACCEPTED);
  5018. }
  5019. //----------------------------------------------------------------------------
  5020. VOID
  5021. SumMdlLengths (
  5022. IN PMDL pMdl,
  5023. IN ULONG BytesCopied,
  5024. IN tCONNECTELE *pConnectEle
  5025. )
  5026. /*++
  5027. Routine Description:
  5028. This routine is called to sum the lengths of MDLs in a chain.
  5029. Arguments:
  5030. Return Value:
  5031. NTSTATUS - Status of event indication
  5032. --*/
  5033. {
  5034. ULONG TotalLength;
  5035. TotalLength = 0;
  5036. do
  5037. {
  5038. if ((TotalLength + MmGetMdlByteCount(pMdl)) > BytesCopied)
  5039. {
  5040. pConnectEle->OffsetFromStart = BytesCopied - TotalLength;
  5041. pConnectEle->pNextMdl = pMdl;
  5042. break;
  5043. }
  5044. else
  5045. {
  5046. TotalLength += MmGetMdlByteCount(pMdl);
  5047. }
  5048. }
  5049. while (pMdl=(PMDL)pMdl->Next);
  5050. return;
  5051. }
  5052. //----------------------------------------------------------------------------
  5053. VOID
  5054. MakePartialMdl (
  5055. IN tCONNECTELE *pConnEle,
  5056. IN PIRP pIrp,
  5057. IN ULONG ToCopy
  5058. )
  5059. /*++
  5060. Routine Description:
  5061. This routine is called to build a partial Mdl that accounts for ToCopy
  5062. bytes of data being copied to the start of the Client's Mdl.
  5063. Arguments:
  5064. pConnEle - ptr to the connection element
  5065. Return Value:
  5066. NTSTATUS - Status of event indication
  5067. --*/
  5068. {
  5069. PMDL pNewMdl;
  5070. PVOID NewAddress;
  5071. // Build a partial Mdl to represent the client's Mdl chain since
  5072. // we have copied data to it, and the transport must copy
  5073. // more data to it after that data.
  5074. //
  5075. SumMdlLengths(pIrp->MdlAddress,ToCopy,pConnEle);
  5076. // this routine has set the Mdl that the next data starts at and
  5077. // the offset from the start of that Mdl, so create a partial Mdl
  5078. // to map that buffer and tack it on the mdl chain instead of the
  5079. // original
  5080. //
  5081. pNewMdl = pConnEle->pNewMdl;
  5082. NewAddress = (PVOID)((PUCHAR)MmGetMdlVirtualAddress(pConnEle->pNextMdl)
  5083. + pConnEle->OffsetFromStart);
  5084. if ((MmGetMdlByteCount(pConnEle->pNextMdl) - pConnEle->OffsetFromStart) > MAXUSHORT)
  5085. {
  5086. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,MAXUSHORT);
  5087. }
  5088. else
  5089. {
  5090. IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,0);
  5091. }
  5092. // hook the new partial mdl to the front of the MDL chain
  5093. //
  5094. pNewMdl->Next = pConnEle->pNextMdl->Next;
  5095. pIrp->MdlAddress = pNewMdl;
  5096. ASSERT(pNewMdl);
  5097. }
  5098. //----------------------------------------------------------------------------
  5099. VOID
  5100. CopyToStartofIndicate (
  5101. IN tLOWERCONNECTION *pLowerConn,
  5102. IN ULONG DataTaken
  5103. )
  5104. /*++
  5105. Routine Description:
  5106. This routine is called to copy data remaining in the indicate buffer to
  5107. the head of the indicate buffer.
  5108. Arguments:
  5109. pLowerConn - ptr to the lower connection element
  5110. Return Value:
  5111. none
  5112. --*/
  5113. {
  5114. PVOID pSrc;
  5115. ULONG DataLeft;
  5116. PVOID pMdl;
  5117. DataLeft = pLowerConn->BytesInIndicate;
  5118. pMdl = (PVOID)MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
  5119. pSrc = (PVOID)( (PUCHAR)pMdl + DataTaken);
  5120. CTEMemCopy(pMdl,pSrc,DataLeft);
  5121. }
  5122. //----------------------------------------------------------------------------
  5123. ULONG FailuresSinceLastLog = 0;
  5124. NTSTATUS
  5125. OutOfRsrcKill(
  5126. OUT tLOWERCONNECTION *pLowerConn)
  5127. /*++
  5128. Routine Description:
  5129. This Routine handles killing a connection when an out of resource condition
  5130. occurs. It uses a special Irp that it has saved away, and a linked list
  5131. if that irp is currently in use.
  5132. Arguments:
  5133. Return Value:
  5134. NTSTATUS - status of the request
  5135. --*/
  5136. {
  5137. NTSTATUS status;
  5138. CTELockHandle OldIrq;
  5139. CTELockHandle OldIrq1;
  5140. PIRP pIrp;
  5141. PFILE_OBJECT pFileObject;
  5142. PDEVICE_OBJECT pDeviceObject;
  5143. tDEVICECONTEXT *pDeviceContext = pLowerConn->pDeviceContext;
  5144. CTESystemTime CurrentTime;
  5145. CTESpinLock(pDeviceContext,OldIrq);
  5146. CTESpinLock(&NbtConfig,OldIrq1);
  5147. //
  5148. // If we have not logged any event recently, then log an event!
  5149. //
  5150. CTEQuerySystemTime (CurrentTime);
  5151. FailuresSinceLastLog++;
  5152. if (pLowerConn->pUpperConnection && // Log it only when the connection hasn't been disconnected
  5153. (CurrentTime.QuadPart-NbtConfig.LastOutOfRsrcLogTime.QuadPart) > ((ULONGLONG) ONE_HOUR*10000))
  5154. {
  5155. NbtLogEvent (EVENT_NBT_NO_RESOURCES, FailuresSinceLastLog, 0x117);
  5156. NbtConfig.LastOutOfRsrcLogTime = CurrentTime;
  5157. FailuresSinceLastLog = 0;
  5158. }
  5159. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_OUT_OF_RSRC);
  5160. if (NbtConfig.OutOfRsrc.pIrp)
  5161. {
  5162. // get an Irp to send the message in
  5163. pIrp = NbtConfig.OutOfRsrc.pIrp;
  5164. NbtConfig.OutOfRsrc.pIrp = NULL;
  5165. pFileObject = pLowerConn->pFileObject;
  5166. ASSERT (pFileObject->Type == IO_TYPE_FILE);
  5167. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  5168. CTESpinFree(&NbtConfig,OldIrq1);
  5169. CTESpinFree(pDeviceContext,OldIrq);
  5170. // store some context stuff in the Irp stack so we can call the completion
  5171. // routine set by the Udpsend code...
  5172. TdiBuildDisconnect(
  5173. pIrp,
  5174. pDeviceObject,
  5175. pFileObject,
  5176. RsrcKillCompletion,
  5177. pLowerConn, //context value passed to completion routine
  5178. NULL, // Timeout...
  5179. TDI_DISCONNECT_ABORT,
  5180. NULL, // send connection info
  5181. NULL); // return connection info
  5182. CHECK_PTR(pIrp);
  5183. pIrp->MdlAddress = NULL;
  5184. CHECK_COMPLETION(pIrp);
  5185. status = IoCallDriver(pDeviceObject,pIrp);
  5186. IF_DBG(NBT_DEBUG_REF)
  5187. KdPrint(("Nbt.OutOfRsrcKill: Kill connection, %X\n",pLowerConn));
  5188. return(status);
  5189. }
  5190. else
  5191. {
  5192. //
  5193. // The lower conn could get removed here, then get dequed from the ConnectionHead and come here
  5194. // (via DpcNextOutOfRsrcKill), and fail to get an Irp; we re-enque it into the OutOfRsrc list,
  5195. // but should not try to deque it here.
  5196. //
  5197. if (!pLowerConn->OutOfRsrcFlag)
  5198. {
  5199. RemoveEntryList(&pLowerConn->Linkage);
  5200. //
  5201. // The lower conn gets removed from the inactive list here and again when
  5202. // DelayedCleanupAfterDisconnect calls NbtDeleteLowerConn. In order to prevent
  5203. // the second deque, we set a flag here and test for it in NbtDeleteLowerConn.
  5204. //
  5205. pLowerConn->OutOfRsrcFlag = TRUE;
  5206. }
  5207. pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (PLIST_ENTRY)0x00006041;
  5208. InsertTailList(&NbtConfig.OutOfRsrc.ConnectionHead,&pLowerConn->Linkage);
  5209. CTESpinFree(&NbtConfig,OldIrq1);
  5210. CTESpinFree(pDeviceContext,OldIrq);
  5211. }
  5212. return(STATUS_SUCCESS);
  5213. }
  5214. //----------------------------------------------------------------------------
  5215. NTSTATUS
  5216. RsrcKillCompletion(
  5217. IN PDEVICE_OBJECT DeviceObject,
  5218. IN PIRP pIrp,
  5219. IN PVOID pContext
  5220. )
  5221. /*++
  5222. Routine Description:
  5223. This routine handles the completion of a disconnect to the transport.
  5224. Arguments:
  5225. Return Value:
  5226. NTSTATUS - success or not
  5227. --*/
  5228. {
  5229. NTSTATUS status;
  5230. KIRQL OldIrq;
  5231. PLIST_ENTRY pEntry;
  5232. tLOWERCONNECTION *pLowerConn;
  5233. PKDPC pDpc;
  5234. pLowerConn = (tLOWERCONNECTION *)pContext;
  5235. // this call will indicate the disconnect to the client and clean up
  5236. // abit.
  5237. //
  5238. status = DisconnectHndlrNotOs (NULL,
  5239. (PVOID)pLowerConn,
  5240. 0,
  5241. NULL,
  5242. 0,
  5243. NULL,
  5244. TDI_DISCONNECT_ABORT);
  5245. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_OUT_OF_RSRC, FALSE);
  5246. CTESpinLock(&NbtConfig,OldIrq);
  5247. NbtConfig.OutOfRsrc.pIrp = pIrp;
  5248. if (!IsListEmpty(&NbtConfig.OutOfRsrc.ConnectionHead))
  5249. {
  5250. if (NbtConfig.OutOfRsrc.pDpc)
  5251. {
  5252. pDpc = NbtConfig.OutOfRsrc.pDpc;
  5253. NbtConfig.OutOfRsrc.pDpc = NULL;
  5254. pEntry = RemoveHeadList(&NbtConfig.OutOfRsrc.ConnectionHead);
  5255. pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
  5256. pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (PLIST_ENTRY)0x00006109;
  5257. KeInitializeDpc(pDpc, DpcNextOutOfRsrcKill, (PVOID)pLowerConn);
  5258. KeInsertQueueDpc(pDpc,NULL,NULL);
  5259. CTESpinFree(&NbtConfig,OldIrq);
  5260. }
  5261. else
  5262. {
  5263. CTESpinFree(&NbtConfig,OldIrq);
  5264. }
  5265. }
  5266. else
  5267. {
  5268. CTESpinFree(&NbtConfig,OldIrq);
  5269. }
  5270. //
  5271. // return this status to stop the IO subsystem from further processing the
  5272. // IRP - i.e. trying to complete it back to the initiating thread! -since
  5273. // there is no initiating thread - we are the initiator
  5274. //
  5275. return(STATUS_MORE_PROCESSING_REQUIRED);
  5276. }
  5277. //----------------------------------------------------------------------------
  5278. VOID
  5279. DpcNextOutOfRsrcKill(
  5280. IN PKDPC pDpc,
  5281. IN PVOID Context,
  5282. IN PVOID SystemArgument1,
  5283. IN PVOID SystemArgument2
  5284. )
  5285. /*++
  5286. Routine Description:
  5287. This routine simply calls OutOfRsrcKill from a Dpc started in
  5288. RsrcKillCompletion.
  5289. Arguments:
  5290. Return Value:
  5291. --*/
  5292. {
  5293. KIRQL OldIrq;
  5294. tLOWERCONNECTION *pLowerConn;
  5295. pLowerConn = (tLOWERCONNECTION *)Context;
  5296. CTESpinLock(&NbtConfig,OldIrq);
  5297. NbtConfig.OutOfRsrc.pDpc = pDpc;
  5298. CTESpinFree(&NbtConfig,OldIrq);
  5299. OutOfRsrcKill(pLowerConn);
  5300. //
  5301. // to remove the extra reference put on pLowerConn when OutOfRsrc called
  5302. //
  5303. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_OUT_OF_RSRC, FALSE);
  5304. }
  5305. //----------------------------------------------------------------------------
  5306. VOID
  5307. NbtCancelFillIrpRoutine(
  5308. IN PDEVICE_OBJECT DeviceContext,
  5309. IN PIRP pIrp
  5310. )
  5311. /*++
  5312. Routine Description:
  5313. This routine handles the cancelling a Receive Irp that has been saved
  5314. during the FILL_IRP state. It must release the
  5315. cancel spin lock before returning re: IoCancelIrp().
  5316. Arguments:
  5317. Return Value:
  5318. The final status from the operation.
  5319. --*/
  5320. {
  5321. tCONNECTELE *pConnEle;
  5322. KIRQL OldIrq;
  5323. KIRQL OldIrq1;
  5324. KIRQL OldIrq2;
  5325. PIO_STACK_LOCATION pIrpSp;
  5326. tLOWERCONNECTION *pLowerConn;
  5327. BOOLEAN CompleteIt = FALSE;
  5328. IF_DBG(NBT_DEBUG_INDICATEBUFF)
  5329. KdPrint(("Nbt.NbtCancelFillIrpRoutine: Got a Receive Cancel Irp !!! *****************\n"));
  5330. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  5331. pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
  5332. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  5333. if (!NBT_VERIFY_HANDLE2 (pConnEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
  5334. {
  5335. ASSERTMSG ("Nbt.NbtCancelFillIrpRoutine: ERROR - Invalid Connection Handle\n", 0);
  5336. // complete the irp
  5337. pIrp->IoStatus.Status = STATUS_INVALID_HANDLE;
  5338. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  5339. return;
  5340. }
  5341. // now look for an Irp to cancel
  5342. //
  5343. CHECK_PTR(pConnEle);
  5344. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  5345. CTESpinLock(pConnEle,OldIrq);
  5346. pLowerConn = pConnEle->pLowerConnId;
  5347. if (pLowerConn)
  5348. {
  5349. CTESpinLock(pLowerConn,OldIrq2);
  5350. SET_STATERCV_LOWER(pLowerConn, INDICATE_BUFFER, RejectAnyData);
  5351. }
  5352. pConnEle->pIrpRcv = NULL;
  5353. if (pLowerConn)
  5354. {
  5355. CTESpinFree(pLowerConn,OldIrq2);
  5356. }
  5357. CTESpinFree(pConnEle,OldIrq);
  5358. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  5359. // complete the irp
  5360. pIrp->IoStatus.Status = STATUS_CANCELLED;
  5361. IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
  5362. if (pLowerConn)
  5363. {
  5364. //
  5365. // Cancelling a Rcv Irp in the fill irp state will cause netbt
  5366. // to lose track of where it is in the message so it must kill
  5367. // the connection.
  5368. //
  5369. OutOfRsrcKill(pLowerConn);
  5370. }
  5371. return;
  5372. }