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.

3126 lines
91 KiB

  1. /*
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. dsi.c
  5. Abstract:
  6. This module contains the routines that implement the Data Stream Interface
  7. (DSI) for AFP/TCP.
  8. Author:
  9. Shirish Koti
  10. Revision History:
  11. 22 Jan 1998 Initial Version
  12. --*/
  13. #define FILENUM FILE_TCPDSI
  14. #include <afp.h>
  15. /*** DsiAfpSetStatus
  16. *
  17. * This routine is a direct call-in from AFP.
  18. * It frees up the earlier status buffer, if any, and stores the new status as
  19. * given by AFP into a new buffer
  20. *
  21. * Parm IN: Context - unused (Appletalk interface compatibility)
  22. * pStatusBuf - the buffer containing new status
  23. * StsBufSize - size of this buffer
  24. *
  25. * Returns: status of operation
  26. *
  27. */
  28. NTSTATUS
  29. DsiAfpSetStatus(
  30. IN PVOID Context,
  31. IN PUCHAR pStatusBuf,
  32. IN USHORT StsBufSize
  33. )
  34. {
  35. PBYTE pBuffer;
  36. PBYTE pOldBuffer;
  37. KIRQL OldIrql;
  38. pBuffer = AfpAllocNonPagedMemory(StsBufSize);
  39. if (pBuffer == NULL)
  40. {
  41. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  42. ("DsiAfpSetStatus: malloc failed\n"));
  43. return(STATUS_INSUFFICIENT_RESOURCES);
  44. }
  45. RtlCopyMemory(pBuffer, pStatusBuf, StsBufSize);
  46. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  47. pOldBuffer = DsiStatusBuffer;
  48. DsiStatusBuffer = pBuffer;
  49. DsiStatusBufferSize = StsBufSize;
  50. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  51. if (pOldBuffer)
  52. {
  53. AfpFreeMemory(pOldBuffer);
  54. }
  55. return(STATUS_SUCCESS);
  56. }
  57. /*** DsiAfpCloseConn
  58. *
  59. * This routine is a direct call-in from AFP.
  60. * It honors AFP's request to close the session down
  61. *
  62. * Parm IN: pTcpConn - the connection context to close
  63. *
  64. * Returns: status of operation
  65. *
  66. */
  67. NTSTATUS
  68. DsiAfpCloseConn(
  69. IN PTCPCONN pTcpConn
  70. )
  71. {
  72. KIRQL OldIrql;
  73. NTSTATUS status=STATUS_SUCCESS;
  74. BOOLEAN fAlreadyDown=TRUE;
  75. ASSERT(VALID_TCPCONN(pTcpConn));
  76. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  77. if (pTcpConn->con_State & TCPCONN_STATE_NOTIFY_AFP)
  78. {
  79. fAlreadyDown = FALSE;
  80. pTcpConn->con_State &= ~TCPCONN_STATE_NOTIFY_AFP;
  81. pTcpConn->con_State |= TCPCONN_STATE_TICKLES_STOPPED;
  82. }
  83. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  84. if (!fAlreadyDown)
  85. {
  86. status = DsiSendDsiRequest(pTcpConn, 0, 0, NULL,DSI_COMMAND_CLOSESESSION);
  87. }
  88. return(status);
  89. }
  90. /*** DsiAfpFreeConn
  91. *
  92. * This routine is a direct call-in from AFP.
  93. * With this call, AFP tells DSI that its connection is being freed. We can
  94. * now remove the refcount on pTcpConn that we had put to protect AFP's context
  95. *
  96. * Parm IN: pTcpConn - the connection context to close
  97. *
  98. * Returns: status of operation
  99. *
  100. */
  101. NTSTATUS
  102. DsiAfpFreeConn(
  103. IN PTCPCONN pTcpConn
  104. )
  105. {
  106. ASSERT(VALID_TCPCONN(pTcpConn));
  107. // remove AFP refcount
  108. DsiDereferenceConnection(pTcpConn);
  109. DBGREFCOUNT(("DsiAfpFreeConn: AFP dec %lx (%d %d,%d)\n",
  110. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  111. return(STATUS_SUCCESS);
  112. }
  113. /*** DsiAfpListenControl
  114. *
  115. * This routine is a direct call-in from AFP.
  116. * It honors AFP's request to either enable or disable "listens". We don't do
  117. * anything fancy here: simply toggle a global variable.
  118. *
  119. * Parm IN: Context - unused (Appletalk interface compatibility)
  120. * Enable - enable or disable?
  121. *
  122. * Returns: status of operation
  123. *
  124. */
  125. NTSTATUS FASTCALL
  126. DsiAfpListenControl(
  127. IN PVOID Context,
  128. IN BOOLEAN Enable
  129. )
  130. {
  131. KIRQL OldIrql;
  132. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  133. DsiTcpEnabled = Enable;
  134. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  135. // update the status buffer, since listen is now enabled or disabled
  136. DsiScheduleWorkerEvent(DsiUpdateAfpStatus, NULL);
  137. return(STATUS_SUCCESS);
  138. }
  139. /*** DsiAfpWriteContinue
  140. *
  141. * This routine is a direct call-in from AFP.
  142. * AFP calls this routine to tell that a previous request to allocate
  143. * Mdl (and buffer) has completed and that whatever action was postponed can
  144. * now continue
  145. *
  146. * Parm IN: pRequest - pointer to the request structure
  147. *
  148. * Returns: status of operation
  149. *
  150. */
  151. NTSTATUS FASTCALL
  152. DsiAfpWriteContinue(
  153. IN PREQUEST pRequest
  154. )
  155. {
  156. KIRQL OldIrql;
  157. NTSTATUS status=STATUS_SUCCESS;
  158. PDSIREQ pDsiReq;
  159. PTCPCONN pTcpConn;
  160. PDEVICE_OBJECT pDeviceObject;
  161. PIRP pIrp;
  162. BOOLEAN fAbortConnection=FALSE;
  163. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  164. ("DsiAfpWriteContinue: entered with pRequest = %lx\n",pRequest));
  165. pDsiReq = CONTAINING_RECORD(pRequest, DSIREQ, dsi_AfpRequest);
  166. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  167. pTcpConn = pDsiReq->dsi_pTcpConn;
  168. ASSERT(VALID_TCPCONN(pTcpConn));
  169. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  170. ASSERT(pTcpConn->con_RcvState == DSI_AWAITING_WRITE_MDL);
  171. ASSERT(pDsiReq == pTcpConn->con_pDsiReq);
  172. ASSERT(!(pTcpConn->con_State & TCPCONN_STATE_TCP_HAS_IRP));
  173. pTcpConn->con_RcvState = DSI_PARTIAL_WRITE;
  174. //
  175. // if connection is closing or if Mdl alloc failed, not much we can do but
  176. // to abort the connection!
  177. //
  178. if ((pTcpConn->con_State & TCPCONN_STATE_CLOSING) ||
  179. (pRequest->rq_WriteMdl == NULL))
  180. {
  181. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  182. ("DsiAfpWriteContinue: aborting conn! %lx\n",pRequest));
  183. fAbortConnection = TRUE;
  184. }
  185. else
  186. {
  187. ASSERT(AfpMdlChainSize(pRequest->rq_WriteMdl) == pDsiReq->dsi_WriteLen);
  188. pIrp = DsiGetIrpForTcp(pTcpConn, NULL, pRequest->rq_WriteMdl, pDsiReq->dsi_WriteLen);
  189. if (pIrp == NULL)
  190. {
  191. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  192. ("DsiAfpWriteContinue: irp alloc failed, aborting connection\n"));
  193. fAbortConnection = TRUE;
  194. }
  195. }
  196. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  197. if (fAbortConnection)
  198. {
  199. DsiAbortConnection(pTcpConn);
  200. return(STATUS_INSUFFICIENT_RESOURCES);
  201. }
  202. pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
  203. // since we are calling IoCallDriver, undo what was done to this irp!
  204. IoSkipCurrentIrpStackLocation(pIrp)
  205. //
  206. // hand over the irp to tell TCP to fill our buffer
  207. //
  208. IoCallDriver(pDeviceObject,pIrp);
  209. return(status);
  210. }
  211. /*** DsiAfpReply
  212. *
  213. * This routine is a direct call-in from AFP.
  214. * It honors AFP's request to send a reply to the client. When TCP completes
  215. * our send (that contains AFP's reply), then we complete this reply for AFP
  216. * (i.e. call AFP's completion routine)
  217. *
  218. * Parm IN: pRequest - pointer to the request structure
  219. * pResultCode - error code (ErrorCode field of DSI header)
  220. *
  221. * Returns: status of operation
  222. *
  223. */
  224. NTSTATUS FASTCALL
  225. DsiAfpReply(
  226. IN PREQUEST pRequest,
  227. IN PBYTE pResultCode
  228. )
  229. {
  230. NTSTATUS status;
  231. PDSIREQ pDsiReq;
  232. KIRQL OldIrql;
  233. PBYTE pPacket;
  234. PTCPCONN pTcpConn;
  235. PMDL pMdl;
  236. DWORD DataLen;
  237. DWORD SendLen;
  238. BOOLEAN fWeAllocated=FALSE;
  239. pDsiReq = CONTAINING_RECORD(pRequest, DSIREQ, dsi_AfpRequest);
  240. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  241. pTcpConn = pDsiReq->dsi_pTcpConn;
  242. ASSERT(VALID_TCPCONN(pTcpConn));
  243. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  244. if (pTcpConn->con_State & TCPCONN_STATE_CLOSING)
  245. {
  246. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  247. DsiAfpReplyCompletion(NULL, NULL, pDsiReq);
  248. return(STATUS_SUCCESS);
  249. }
  250. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  251. //
  252. // we need to append our own Mdl (for DSI header) if the outgoing data
  253. // is part of cache mgr's Mdl
  254. //
  255. if (pRequest->rq_CacheMgrContext)
  256. {
  257. pPacket = &pDsiReq->dsi_RespHeader[0];
  258. if (pDsiReq->dsi_AfpRequest.rq_ReplyMdl)
  259. {
  260. DataLen = AfpMdlChainSize(pDsiReq->dsi_AfpRequest.rq_ReplyMdl);
  261. }
  262. else
  263. {
  264. DataLen = 0;
  265. }
  266. SendLen = DataLen + DSI_HEADER_SIZE;
  267. pMdl = AfpAllocMdl(pPacket, DSI_HEADER_SIZE, NULL);
  268. if (pMdl == NULL)
  269. {
  270. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  271. ("DsiAfpReply: mdl alloc failed!\n"));
  272. DsiAfpReplyCompletion(NULL, NULL, pDsiReq);
  273. DsiAbortConnection(pTcpConn);
  274. return(STATUS_INSUFFICIENT_RESOURCES);
  275. }
  276. // link in Afp's mdl
  277. pMdl->Next = pDsiReq->dsi_AfpRequest.rq_ReplyMdl;
  278. pDsiReq->dsi_pDsiAllocedMdl = pMdl;
  279. fWeAllocated = TRUE;
  280. }
  281. else
  282. {
  283. pMdl = pDsiReq->dsi_AfpRequest.rq_ReplyMdl;
  284. if (pMdl)
  285. {
  286. //
  287. // get the total length of the send, which include the DSI header size
  288. //
  289. SendLen = AfpMdlChainSize(pMdl);
  290. ASSERT(SendLen >= DSI_HEADER_SIZE);
  291. DataLen = SendLen - DSI_HEADER_SIZE;
  292. pPacket = MmGetSystemAddressForMdlSafe(
  293. pMdl,
  294. NormalPagePriority);
  295. if (pPacket == NULL)
  296. {
  297. status = STATUS_INSUFFICIENT_RESOURCES;
  298. goto error_end;
  299. }
  300. #if DBG
  301. // make sure we allocated room for the DSI header!
  302. ASSERT(*(DWORD *)pPacket == 0x081294);
  303. #endif
  304. }
  305. else
  306. {
  307. pPacket = &pDsiReq->dsi_RespHeader[0];
  308. SendLen = DSI_HEADER_SIZE;
  309. DataLen = 0;
  310. pMdl = AfpAllocMdl(pPacket, SendLen, NULL);
  311. if (pMdl == NULL)
  312. {
  313. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  314. ("DsiAfpReply: mdl alloc failed!\n"));
  315. DsiAfpReplyCompletion(NULL, NULL, pDsiReq);
  316. DsiAbortConnection(pTcpConn);
  317. return(STATUS_INSUFFICIENT_RESOURCES);
  318. }
  319. pDsiReq->dsi_pDsiAllocedMdl = pMdl;
  320. fWeAllocated = TRUE;
  321. }
  322. }
  323. //
  324. // form the DSI header
  325. //
  326. pPacket[DSI_OFFSET_FLAGS] = DSI_REPLY;
  327. pPacket[DSI_OFFSET_COMMAND] = pDsiReq->dsi_Command;
  328. PUTSHORT2SHORT(&pPacket[DSI_OFFSET_REQUESTID], pDsiReq->dsi_RequestID);
  329. *(DWORD *)&pPacket[DSI_OFFSET_DATAOFFSET] = *(DWORD *)pResultCode;
  330. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_DATALEN], DataLen);
  331. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_RESERVED], 0);
  332. status = DsiTdiSend(pTcpConn,
  333. pMdl,
  334. SendLen,
  335. DsiAfpReplyCompletion,
  336. pDsiReq);
  337. error_end:
  338. if (!NT_SUCCESS(status))
  339. {
  340. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  341. ("DsiAfpReply: DsiTdiSend failed %lx\n",status));
  342. if (fWeAllocated)
  343. {
  344. pMdl->Next = NULL;
  345. AfpFreeMdl(pMdl);
  346. }
  347. DsiAfpReplyCompletion(NULL, NULL, pDsiReq);
  348. status = STATUS_PENDING;
  349. }
  350. return(status);
  351. }
  352. /*** DsiAfpSendAttention
  353. *
  354. * This routine is a direct call-in from AFP.
  355. * It honors AFP's request to send attention to the client.
  356. *
  357. * Parm IN: pTcpConn - the connection context to close
  358. * AttentionWord - attention word to send
  359. * pContext - context, to be supplied at completion time
  360. *
  361. * Returns: status of operation
  362. *
  363. */
  364. NTSTATUS
  365. DsiAfpSendAttention(
  366. IN PTCPCONN pTcpConn,
  367. IN USHORT AttentionWord,
  368. IN PVOID pContext
  369. )
  370. {
  371. NTSTATUS status;
  372. ASSERT(VALID_TCPCONN(pTcpConn));
  373. status = DsiSendDsiRequest(pTcpConn,
  374. sizeof(USHORT),
  375. AttentionWord,
  376. pContext,
  377. DSI_COMMAND_ATTENTION);
  378. return(status);
  379. }
  380. /*** DsiAcceptConnection
  381. *
  382. * This routine accepts (or rejects) an incoming tcp connection request.
  383. * Basically, after making a few checks, a (pre-allocated) connection object
  384. * is dequeued and returned as our context to TCP.
  385. *
  386. * Parm IN: pTcpAdptr - adapter
  387. * MacIpAddr - ipaddr of the Mac that's connecting
  388. *
  389. * Parm OUT: ppRetTcpCon - connection object we are returning as context
  390. *
  391. * Returns: status of operation
  392. *
  393. */
  394. NTSTATUS
  395. DsiAcceptConnection(
  396. IN PTCPADPTR pTcpAdptr,
  397. IN IPADDRESS MacIpAddr,
  398. OUT PTCPCONN *ppRetTcpConn
  399. )
  400. {
  401. NTSTATUS status=STATUS_SUCCESS;
  402. KIRQL OldIrql;
  403. PTCPCONN pTcpConn;
  404. PLIST_ENTRY pList;
  405. DWORD dwReplCount=0;
  406. DWORD i;
  407. BOOLEAN fReplenish=FALSE;
  408. *ppRetTcpConn = NULL;
  409. // if the server is disabled, don't accept this connection
  410. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  411. if (!DsiTcpEnabled)
  412. {
  413. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  414. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  415. ("DsiAcceptConnection: Server is disabled\n"));
  416. return(STATUS_DATA_NOT_ACCEPTED);
  417. }
  418. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  419. ACQUIRE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, &OldIrql);
  420. //
  421. // if the adapter is closing, don't accept this connection
  422. //
  423. if (pTcpAdptr->adp_State & TCPADPTR_STATE_CLOSING)
  424. {
  425. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  426. ("DsiAcceptConnection: %lx is closing, rejecting connection\n",pTcpAdptr));
  427. goto DsiAcceptConnection_ErrExit;
  428. }
  429. //
  430. // do we have a connection object available in the free list?
  431. //
  432. if (IsListEmpty(&pTcpAdptr->adp_FreeConnHead))
  433. {
  434. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  435. ("DsiAcceptConnection: FreeConnHead empty, rejecting connection\n"));
  436. goto DsiAcceptConnection_ErrExit;
  437. }
  438. pList = RemoveHeadList(&pTcpAdptr->adp_FreeConnHead);
  439. ASSERT(pTcpAdptr->adp_NumFreeConnections > 0);
  440. pTcpAdptr->adp_NumFreeConnections--;
  441. pTcpConn = CONTAINING_RECORD(pList, TCPCONN, con_Linkage);
  442. ACQUIRE_SPIN_LOCK_AT_DPC(&pTcpConn->con_SpinLock);
  443. // put TCP CLIENT-FIN refcount, removed after TCP tells us it got client's FIN
  444. pTcpConn->con_RefCount++;
  445. DBGREFCOUNT(("DsiAcceptConnection: CLIENT-FIN inc %lx (%d %d,%d)\n",
  446. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  447. // put TCP SRVR-FIN refcount, removed after TCP tells us it sent out FIN
  448. pTcpConn->con_RefCount++;
  449. DBGREFCOUNT(("DsiAcceptConnection: SRVR-FIN inc %lx (%d %d,%d)\n",
  450. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  451. // put ACCEPT refcount, removed after TCP calls our accept completion
  452. pTcpConn->con_RefCount++;
  453. DBGREFCOUNT(("DsiAcceptConnection: ACCEPT inc %lx (%d %d,%d)\n",
  454. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  455. pTcpConn->con_State |= (TCPCONN_STATE_CONNECTED | TCPCONN_STATE_NOTIFY_TCP);
  456. pTcpConn->con_DestIpAddr = MacIpAddr;
  457. //
  458. // put this connection on the active list (though this isn't fully active yet)
  459. //
  460. InsertTailList(&pTcpAdptr->adp_ActiveConnHead, &pTcpConn->con_Linkage);
  461. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  462. if (pTcpAdptr->adp_NumFreeConnections < DSI_INIT_FREECONNLIST_SIZE)
  463. {
  464. //
  465. // we are going to create a new connection in the free list to replenish
  466. // the one we just used up: make sure adapter stays around when that
  467. // delayed event fires!
  468. //
  469. pTcpAdptr->adp_RefCount++;
  470. fReplenish = TRUE;
  471. }
  472. else
  473. {
  474. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  475. ("DsiAcceptConnection: at or above limit (%d): NOT replenishing\n",
  476. pTcpAdptr->adp_NumFreeConnections));
  477. }
  478. RELEASE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, OldIrql);
  479. if (fReplenish)
  480. {
  481. //
  482. // now schedule that event to replenish the connection...
  483. //
  484. DsiScheduleWorkerEvent(DsiCreateTcpConn, pTcpAdptr);
  485. }
  486. *ppRetTcpConn = pTcpConn;
  487. ACQUIRE_SPIN_LOCK(&DsiResourceLock, &OldIrql);
  488. DsiNumTcpConnections++;
  489. RELEASE_SPIN_LOCK(&DsiResourceLock, OldIrql);
  490. return(STATUS_SUCCESS);
  491. //
  492. // Error case
  493. //
  494. DsiAcceptConnection_ErrExit:
  495. if (pTcpAdptr->adp_NumFreeConnections < DSI_INIT_FREECONNLIST_SIZE)
  496. {
  497. dwReplCount = (DSI_INIT_FREECONNLIST_SIZE - pTcpAdptr->adp_NumFreeConnections);
  498. pTcpAdptr->adp_RefCount += dwReplCount;
  499. fReplenish = TRUE;
  500. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  501. ("DsiAcceptConnection: below limit (%d): replenishing %d times\n",
  502. pTcpAdptr->adp_NumFreeConnections,dwReplCount));
  503. }
  504. RELEASE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, OldIrql);
  505. if (fReplenish)
  506. {
  507. for (i=0; i<dwReplCount; i++)
  508. {
  509. DsiScheduleWorkerEvent(DsiCreateTcpConn, pTcpAdptr);
  510. }
  511. }
  512. return(STATUS_DATA_NOT_ACCEPTED);
  513. }
  514. /*** DsiProcessData
  515. *
  516. * This routine is the main data processing state machine. Since TCP is a
  517. * streaming protocol, there is no guarantee that whatever the client sent
  518. * can come in in one piece. That's why the states. Here's what they mean:
  519. *
  520. * DSI_NEW_REQUEST : init state, waiting for a new request from client
  521. * DSI_PARTIAL_HEADER : we have received only some of the 16 bytes of hdr
  522. * DSI_HDR_COMPLETE : we have the complete header (received all 16 bytes)
  523. * DSI_PARTIAL_COMMAND : we have recvd only some of the request bytes
  524. * DSI_COMMAND_COMPLETE : we have recvd all of the request bytes
  525. * DSI_PARTIAL_WRITE : we have recvd some of the Write bytes
  526. * DSI_WRITE_COMPLETE : we have recvd all of the Write bytes
  527. *
  528. * Parm IN: pTcpConn - the connection object in question
  529. * BytesIndicated - bytes indicated
  530. * BytesAvailable - bytes available (usually same as indicated)
  531. * pBufferFromTcp - pointer to the DSI data
  532. *
  533. * Parm OUT: pBytesAccepted - pointer to how many bytes we consumed
  534. * ppIrp - pointer to an irp pointer, if necessary
  535. *
  536. * Returns: status of operation
  537. *
  538. */
  539. NTSTATUS
  540. DsiProcessData(
  541. IN PTCPCONN pTcpConn,
  542. IN ULONG BytesIndicated,
  543. IN ULONG BytesAvailable,
  544. IN PBYTE pBufferFromTcp,
  545. OUT PULONG pBytesAccepted,
  546. OUT PIRP *ppRetIrp
  547. )
  548. {
  549. KIRQL OldIrql;
  550. NTSTATUS status=STATUS_SUCCESS;
  551. DWORD BytesConsumed=0;
  552. DWORD UnProcessedBytes;
  553. DWORD BytesNeeded;
  554. DWORD BytesActuallyCopied;
  555. PBYTE pStreamPtr;
  556. PBYTE pDestBuffer;
  557. PBYTE pHdrBuf=NULL;
  558. DWORD RequestLen;
  559. PDSIREQ pDsiReq=NULL;
  560. PMDL pMdl;
  561. PIRP pIrp;
  562. BOOLEAN fSomeMoreProcessing=TRUE;
  563. BOOLEAN fTCPHasMore=FALSE;
  564. *ppRetIrp = NULL;
  565. UnProcessedBytes = BytesIndicated;
  566. pStreamPtr = pBufferFromTcp;
  567. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  568. // if we are closing, throw away these bytes
  569. if (pTcpConn->con_State & TCPCONN_STATE_CLOSING)
  570. {
  571. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  572. ("DsiProcessData: dropping data, conn %lx closing\n",pTcpConn));
  573. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  574. *pBytesAccepted = BytesIndicated;
  575. return(STATUS_SUCCESS);
  576. }
  577. //
  578. // this can happen if we are just submitting an irp down, and before the irp
  579. // gets down to TCP, an indicate comes in. Reject this data since our irp is
  580. // on its way.
  581. //
  582. if (pTcpConn->con_State & TCPCONN_STATE_TCP_HAS_IRP)
  583. {
  584. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  585. ("DsiProcessData: TCP has irp, so rejecting indication\n"));
  586. *pBytesAccepted = 0;
  587. pTcpConn->con_BytesWithTcp += BytesAvailable;
  588. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  589. return(STATUS_DATA_NOT_ACCEPTED);
  590. }
  591. //
  592. // if we already know TCP has unconsumed bytes, or if TCP is indicating less
  593. // than what's available, mark the fact that TCP has more stuff with it
  594. //
  595. if (BytesAvailable > BytesIndicated)
  596. {
  597. fTCPHasMore = TRUE;
  598. }
  599. while (fSomeMoreProcessing)
  600. {
  601. fSomeMoreProcessing = FALSE;
  602. switch (pTcpConn->con_RcvState)
  603. {
  604. //
  605. // most common case. We are ready to deal with a new request.
  606. //
  607. case DSI_NEW_REQUEST:
  608. ASSERT(!(pTcpConn->con_State & TCPCONN_STATE_PARTIAL_DATA));
  609. pDsiReq = DsiGetRequest();
  610. if (pDsiReq == NULL)
  611. {
  612. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  613. ("DsiProcessData: DsiGetRequest failed, killing %lx\n",pTcpConn));
  614. goto DsiProcessData_ErrorExit;
  615. }
  616. pDsiReq->dsi_pTcpConn = pTcpConn;
  617. pTcpConn->con_pDsiReq = pDsiReq;
  618. // put a REQUEST refcount - remove when the request is done
  619. pTcpConn->con_RefCount++;
  620. DBGREFCOUNT(("DsiProcessData: REQUEST inc %lx (%d %d,%d)\n",
  621. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  622. //
  623. // do we have the complete header?
  624. //
  625. if (UnProcessedBytes >= DSI_HEADER_SIZE)
  626. {
  627. //
  628. // get info out of the header
  629. //
  630. DSI_PARSE_HEADER(pDsiReq, pStreamPtr);
  631. //
  632. // hack! Mac client 3.7 has a bug where if a 0-byte Write is
  633. // sent to us, the DataOffset field is 0, but Total Data Length
  634. // field is 0xC (or whatever the request length is)
  635. // Put in a workaround!
  636. //
  637. if ((pDsiReq->dsi_Command == DSI_COMMAND_WRITE) &&
  638. (pDsiReq->dsi_RequestLen == 0))
  639. {
  640. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  641. ("DsiProcessData: 0-byte Write hack to workaround Mac's bug\n"));
  642. pDsiReq->dsi_RequestLen = pDsiReq->dsi_WriteLen;
  643. pDsiReq->dsi_WriteLen = 0;
  644. }
  645. // update all the counters and buffers
  646. BytesConsumed += DSI_HEADER_SIZE;
  647. pStreamPtr += DSI_HEADER_SIZE;
  648. UnProcessedBytes -= DSI_HEADER_SIZE;
  649. ASSERT(pStreamPtr <= pBufferFromTcp+BytesIndicated);
  650. pTcpConn->con_RcvState = DSI_HDR_COMPLETE;
  651. // make sure we visit case DSI_HDR_COMPLETE: before leaving
  652. fSomeMoreProcessing = TRUE;
  653. }
  654. //
  655. // yikes, only part of the header has come in
  656. // just set the state and let the parsing loop continue..
  657. //
  658. else
  659. {
  660. pTcpConn->con_State |= TCPCONN_STATE_PARTIAL_DATA;
  661. pTcpConn->con_RcvState = DSI_PARTIAL_HEADER;
  662. pTcpConn->con_pDsiReq->dsi_RequestLen = DSI_HEADER_SIZE;
  663. }
  664. break; // case DSI_NEW_REQUEST:
  665. //
  666. // PartialHeader case is extremely unlikely to occur, given how small
  667. // the header is (16 bytes). But given that we have a streaming
  668. // protocol (TCP) below us, anything is possible.
  669. // PartialCommand is also unlikely for the same reason. However, in
  670. // case of a Write command, we always force PartialCommand state
  671. // since it's very unlikely the whole Write can come in in one packet.
  672. //
  673. case DSI_PARTIAL_HEADER:
  674. case DSI_PARTIAL_COMMAND:
  675. pDsiReq = pTcpConn->con_pDsiReq;
  676. ASSERT(pDsiReq != NULL);
  677. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  678. ASSERT(pTcpConn->con_State & TCPCONN_STATE_PARTIAL_DATA);
  679. //
  680. // if we haven't started copying any bytes in yet then we need
  681. // to get storage room (use built-in buffer if possible)
  682. //
  683. if (pDsiReq->dsi_PartialBufSize == 0)
  684. {
  685. ASSERT(pDsiReq->dsi_PartialBuf == NULL);
  686. if (pDsiReq->dsi_RequestLen <= DSI_BUFF_SIZE)
  687. {
  688. pDsiReq->dsi_PartialBuf = &pDsiReq->dsi_RespHeader[0];
  689. }
  690. //
  691. // allocate a buffer to hold this partial header.
  692. //
  693. else
  694. {
  695. pDsiReq->dsi_PartialBuf =
  696. DsiGetReqBuffer(pDsiReq->dsi_RequestLen);
  697. if (pDsiReq->dsi_PartialBuf == NULL)
  698. {
  699. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  700. ("DsiProcessData: Buffer alloc failed, killing %lx\n",pTcpConn));
  701. goto DsiProcessData_ErrorExit;
  702. }
  703. }
  704. }
  705. //
  706. // how many more bytes do we need to complete this hdr/command
  707. //
  708. BytesNeeded = (pDsiReq->dsi_RequestLen - pDsiReq->dsi_PartialBufSize);
  709. //
  710. // if we don't have enough bytes to satisfy this Command (or Hdr),
  711. // don't copy anything but give an irp back to TCP
  712. //
  713. if (UnProcessedBytes < BytesNeeded)
  714. {
  715. pIrp = DsiGetIrpForTcp(
  716. pTcpConn,
  717. (pDsiReq->dsi_PartialBuf + pDsiReq->dsi_PartialBufSize),
  718. NULL,
  719. BytesNeeded);
  720. if (pIrp == NULL)
  721. {
  722. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  723. ("DsiProcessData: couldn't alloc RcvIrp, killing %lx\n",pTcpConn));
  724. goto DsiProcessData_ErrorExit;
  725. }
  726. pDsiReq->dsi_pDsiAllocedMdl = pIrp->MdlAddress;
  727. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  728. ("DsiProcessData: A irp %lx to TCP for %d bytes (%lx)\n",
  729. pIrp,BytesNeeded,pTcpConn));
  730. *ppRetIrp = pIrp;
  731. *pBytesAccepted = BytesConsumed;
  732. // did TCP call us? then update byte count
  733. if (BytesIndicated)
  734. {
  735. pTcpConn->con_BytesWithTcp += (BytesAvailable - BytesConsumed);
  736. }
  737. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  738. return(STATUS_MORE_PROCESSING_REQUIRED);
  739. }
  740. //
  741. // if the bytes we need are available, copy them in. Then decide
  742. // what to do next (same if we already have the bytes)
  743. //
  744. else if ((UnProcessedBytes > 0) || (BytesNeeded == 0))
  745. {
  746. if (BytesNeeded > 0)
  747. {
  748. ASSERT(pDsiReq->dsi_PartialBufSize == 0);
  749. RtlCopyMemory(
  750. (pDsiReq->dsi_PartialBuf + pDsiReq->dsi_PartialBufSize),
  751. pStreamPtr,
  752. BytesNeeded);
  753. //
  754. // update all the counters and buffers
  755. //
  756. pDsiReq->dsi_PartialBufSize += BytesNeeded;
  757. BytesConsumed += BytesNeeded;
  758. pStreamPtr += BytesNeeded;
  759. UnProcessedBytes -= BytesNeeded;
  760. ASSERT(pStreamPtr <= pBufferFromTcp+BytesIndicated);
  761. }
  762. // we should have all the bytes we need now
  763. ASSERT(pDsiReq->dsi_PartialBufSize == pDsiReq->dsi_RequestLen);
  764. //
  765. // find out what the next rcv state should be
  766. //
  767. if (pTcpConn->con_RcvState == DSI_PARTIAL_HEADER)
  768. {
  769. //
  770. // get info out of the header
  771. //
  772. DSI_PARSE_HEADER(pDsiReq, pDsiReq->dsi_PartialBuf);
  773. //
  774. // hack! Mac client 3.7 has a bug where if a 0-byte Write is
  775. // sent to us, the DataOffset field is 0, but Total Data Length
  776. // field is 0xC (or whatever the request length is)
  777. // Put in a workaround!
  778. //
  779. if ((pDsiReq->dsi_Command == DSI_COMMAND_WRITE) &&
  780. (pDsiReq->dsi_RequestLen == 0))
  781. {
  782. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  783. ("DsiProcessData: 0-byte Write hack to workaround Mac's bug\n"));
  784. pDsiReq->dsi_RequestLen = pDsiReq->dsi_WriteLen;
  785. pDsiReq->dsi_WriteLen = 0;
  786. }
  787. pTcpConn->con_RcvState = DSI_HDR_COMPLETE;
  788. }
  789. //
  790. // no, we were in DSI_PARTIAL_COMMAND, so we will now move
  791. // to DSI_PARTIAL_WRITE if this is a Write command, otherwise
  792. // to DSI_COMMAND_COMPLETE
  793. //
  794. else
  795. {
  796. if (pDsiReq->dsi_Command == DSI_COMMAND_WRITE)
  797. {
  798. pDsiReq->dsi_AfpRequest.rq_RequestBuf =
  799. pDsiReq->dsi_PartialBuf;
  800. pDsiReq->dsi_AfpRequest.rq_RequestSize =
  801. pDsiReq->dsi_PartialBufSize;
  802. //
  803. // for now, assume that AfpCB_GetWriteBuffer will
  804. // return pending and set the state in anticipation
  805. //
  806. pTcpConn->con_RcvState = DSI_AWAITING_WRITE_MDL;
  807. pDsiReq->dsi_PartialWriteSize = 0;
  808. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  809. //
  810. // allocate the write mdl before we move to
  811. // DSI_PARTIAL_WRITE state
  812. //
  813. status = AfpCB_GetWriteBuffer(pTcpConn->con_pSda,
  814. &pDsiReq->dsi_AfpRequest);
  815. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  816. //
  817. // most common case: file server will pend it so it can
  818. // go to cache mgr
  819. //
  820. if (status == STATUS_PENDING)
  821. {
  822. // if TCP has any unconsumed bytes, update our count
  823. if (BytesIndicated > 0)
  824. {
  825. pTcpConn->con_BytesWithTcp +=
  826. (BytesAvailable - BytesConsumed);
  827. }
  828. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  829. *pBytesAccepted = BytesConsumed;
  830. status = (BytesConsumed)?
  831. STATUS_SUCCESS : STATUS_DATA_NOT_ACCEPTED;
  832. return(status);
  833. }
  834. else if (status != STATUS_SUCCESS)
  835. {
  836. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  837. ("DsiProcessData: GetWriteBuffer failed\n"));
  838. pTcpConn->con_RcvState = DSI_PARTIAL_WRITE;
  839. goto DsiProcessData_ErrorExit;
  840. }
  841. //
  842. // AfpCB_GetWriteBuffer succeeded synchronously: set
  843. // the state to partial-write
  844. //
  845. pTcpConn->con_RcvState = DSI_PARTIAL_WRITE;
  846. ASSERT((pDsiReq->dsi_AfpRequest.rq_WriteMdl != NULL) ||
  847. (pDsiReq->dsi_WriteLen == 0));
  848. if (pDsiReq->dsi_WriteLen == 0)
  849. {
  850. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  851. ("DsiProcessData: 0-len write on %lx\n",pDsiReq));
  852. }
  853. }
  854. //
  855. // it's not a Write, but a Command
  856. //
  857. else
  858. {
  859. ASSERT(pDsiReq->dsi_Command == DSI_COMMAND_COMMAND);
  860. pTcpConn->con_RcvState = DSI_COMMAND_COMPLETE;
  861. }
  862. }
  863. // make sure we visit case DSI_HDR_COMPLETE: before leaving
  864. fSomeMoreProcessing = TRUE;
  865. }
  866. break; // case DSI_PARTIAL_HEADER: case DSI_PARTIAL_COMMAND:
  867. //
  868. // we have the full header: see what we must do next
  869. //
  870. case DSI_HDR_COMPLETE:
  871. pDsiReq = pTcpConn->con_pDsiReq;
  872. ASSERT(pDsiReq != NULL);
  873. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  874. if (pTcpConn->con_State & TCPCONN_STATE_PARTIAL_DATA)
  875. {
  876. ASSERT(pDsiReq->dsi_PartialBuf != NULL);
  877. ASSERT(pDsiReq->dsi_PartialBufSize > 0);
  878. if (pDsiReq->dsi_PartialBuf != &pDsiReq->dsi_RespHeader[0])
  879. {
  880. DsiFreeReqBuffer(pDsiReq->dsi_PartialBuf);
  881. }
  882. pDsiReq->dsi_PartialBuf = NULL;
  883. pDsiReq->dsi_PartialBufSize = 0;
  884. }
  885. pTcpConn->con_State &= ~TCPCONN_STATE_PARTIAL_DATA;
  886. if (!DsiValidateHeader(pTcpConn, pDsiReq))
  887. {
  888. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  889. ("DsiProcessData: packet invalid, killing %lx\n",pTcpConn));
  890. goto DsiProcessData_ErrorExit;
  891. }
  892. //
  893. // if this is a Write command, we need to get mdl from AFP
  894. //
  895. if (pDsiReq->dsi_Command == DSI_COMMAND_WRITE)
  896. {
  897. // we need to copy the request bytes
  898. pTcpConn->con_RcvState = DSI_PARTIAL_COMMAND;
  899. pTcpConn->con_State |= TCPCONN_STATE_PARTIAL_DATA;
  900. }
  901. //
  902. // do we have all the bytes needed to complete the request?
  903. //
  904. else if (UnProcessedBytes >= pDsiReq->dsi_RequestLen)
  905. {
  906. pTcpConn->con_RcvState = DSI_COMMAND_COMPLETE;
  907. // make sure we visit case DSI_HDR_COMPLETE: before leaving
  908. fSomeMoreProcessing = TRUE;
  909. }
  910. else
  911. {
  912. pTcpConn->con_RcvState = DSI_PARTIAL_COMMAND;
  913. pTcpConn->con_State |= TCPCONN_STATE_PARTIAL_DATA;
  914. }
  915. break;
  916. //
  917. // we are waiting for Afp to give us an mdl (and buffer), but TCP tells
  918. // us data has arrived: just note the fact, and go back
  919. //
  920. case DSI_AWAITING_WRITE_MDL:
  921. // did TCP call us? then update byte count
  922. if (BytesIndicated)
  923. {
  924. pTcpConn->con_BytesWithTcp += (BytesAvailable - BytesConsumed);
  925. }
  926. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  927. *pBytesAccepted = BytesConsumed;
  928. status = (BytesConsumed)? STATUS_SUCCESS : STATUS_DATA_NOT_ACCEPTED;
  929. return(status);
  930. //
  931. // we are in the middle of a Write command: copy the remaining bytes
  932. // needed to complete the Write, or whatever bytes that have come in
  933. // as the case may be
  934. //
  935. case DSI_PARTIAL_WRITE:
  936. pDsiReq = pTcpConn->con_pDsiReq;
  937. ASSERT(pDsiReq != NULL);
  938. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  939. BytesNeeded = (pDsiReq->dsi_WriteLen - pDsiReq->dsi_PartialWriteSize);
  940. //
  941. // if we don't have enough bytes to satisfy this Write, give irp to
  942. // TCP: TCP will come back when the irp completes
  943. //
  944. if (UnProcessedBytes < BytesNeeded)
  945. {
  946. ASSERT(pDsiReq->dsi_AfpRequest.rq_WriteMdl != NULL);
  947. pIrp = DsiGetIrpForTcp(
  948. pTcpConn,
  949. NULL,
  950. pDsiReq->dsi_AfpRequest.rq_WriteMdl,
  951. BytesNeeded);
  952. if (pIrp == NULL)
  953. {
  954. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  955. ("DsiProcessData: B couldn't alloc RcvIrp, killing %lx\n",pTcpConn));
  956. goto DsiProcessData_ErrorExit;
  957. }
  958. ASSERT(pDsiReq->dsi_pDsiAllocedMdl == NULL);
  959. ASSERT(pIrp->MdlAddress == pDsiReq->dsi_AfpRequest.rq_WriteMdl);
  960. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  961. ("DsiProcessData: B irp for %d bytes,Rem=%d (%lx)\n",
  962. BytesNeeded,pTcpConn->con_BytesWithTcp,pTcpConn));
  963. *ppRetIrp = pIrp;
  964. *pBytesAccepted = BytesConsumed;
  965. // did TCP call us? then update byte count
  966. if (BytesIndicated)
  967. {
  968. pTcpConn->con_BytesWithTcp += (BytesAvailable - BytesConsumed);
  969. }
  970. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  971. return(STATUS_MORE_PROCESSING_REQUIRED);
  972. }
  973. //
  974. // if the bytes we need are available, copy them in. Then decide
  975. // what to do next (same if we already have the bytes)
  976. //
  977. else if ((UnProcessedBytes > 0) || (BytesNeeded == 0))
  978. {
  979. ASSERT(BytesNeeded <= UnProcessedBytes);
  980. if (BytesNeeded > 0)
  981. {
  982. ASSERT(pDsiReq->dsi_PartialWriteSize == 0);
  983. TdiCopyBufferToMdl(pStreamPtr,
  984. 0,
  985. BytesNeeded,
  986. pDsiReq->dsi_AfpRequest.rq_WriteMdl,
  987. pDsiReq->dsi_PartialWriteSize,
  988. &BytesActuallyCopied);
  989. if (BytesActuallyCopied != BytesNeeded)
  990. {
  991. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  992. ("DsiProcessData: Tdi copied %ld instead of %ld\n",
  993. BytesActuallyCopied,BytesNeeded));
  994. goto DsiProcessData_ErrorExit;
  995. }
  996. pDsiReq->dsi_PartialWriteSize += BytesNeeded;
  997. BytesConsumed += BytesActuallyCopied;
  998. pStreamPtr += BytesActuallyCopied;
  999. UnProcessedBytes -= BytesActuallyCopied;
  1000. }
  1001. // at this point, all the bytes needed to satisfy the Write should be in
  1002. ASSERT(pDsiReq->dsi_PartialWriteSize == pDsiReq->dsi_WriteLen);
  1003. pTcpConn->con_RcvState = DSI_WRITE_COMPLETE;
  1004. // make sure we visit case DSI_WRITE_COMPLETE: before leaving
  1005. fSomeMoreProcessing = TRUE;
  1006. }
  1007. ASSERT(pStreamPtr <= pBufferFromTcp+BytesIndicated);
  1008. break; // case DSI_PARTIAL_WRITE:
  1009. case DSI_COMMAND_COMPLETE:
  1010. case DSI_WRITE_COMPLETE:
  1011. pDsiReq = pTcpConn->con_pDsiReq;
  1012. ASSERT(pDsiReq != NULL);
  1013. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  1014. //
  1015. // setup the AfpRequest according whether we buffered the
  1016. // request or whether we are using TCP's buffer
  1017. //
  1018. if (pTcpConn->con_State & TCPCONN_STATE_PARTIAL_DATA)
  1019. {
  1020. ASSERT(pDsiReq->dsi_PartialBufSize != 0);
  1021. ASSERT(pDsiReq->dsi_PartialBuf != NULL);
  1022. ASSERT(pDsiReq->dsi_PartialBufSize == pDsiReq->dsi_RequestLen);
  1023. pDsiReq->dsi_AfpRequest.rq_RequestBuf = pDsiReq->dsi_PartialBuf;
  1024. }
  1025. else
  1026. {
  1027. pDsiReq->dsi_AfpRequest.rq_RequestBuf = pStreamPtr;
  1028. }
  1029. pDsiReq->dsi_AfpRequest.rq_RequestSize = pDsiReq->dsi_RequestLen;
  1030. InsertTailList(&pTcpConn->con_PendingReqs, &pDsiReq->dsi_Linkage);
  1031. pTcpConn->con_pDsiReq = NULL;
  1032. RequestLen = pDsiReq->dsi_RequestLen;
  1033. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1034. //
  1035. // call the routine to take appropriate action, based on what
  1036. // DSI command it is
  1037. // Once we are back from this routine, there is no telling what
  1038. // would have happened to pDsiReq! So don't touch it!
  1039. //
  1040. status = DsiExecuteCommand(pTcpConn, pDsiReq);
  1041. if (!NT_SUCCESS(status))
  1042. {
  1043. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1044. ("DsiProcessData: fatal error %lx, killing %lx\n",status,pTcpConn));
  1045. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1046. RemoveEntryList(&pDsiReq->dsi_Linkage);
  1047. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1048. if (pDsiReq->dsi_AfpRequest.rq_WriteMdl != NULL)
  1049. {
  1050. pDsiReq->dsi_AfpRequest.rq_RequestSize =
  1051. (LONG)pTcpConn->con_DestIpAddr;
  1052. ASSERT(pTcpConn->con_pSda != NULL);
  1053. AfpCB_RequestNotify(STATUS_REMOTE_DISCONNECT,
  1054. pTcpConn->con_pSda,
  1055. &pDsiReq->dsi_AfpRequest);
  1056. }
  1057. DsiAbortConnection(pTcpConn);
  1058. DsiFreeRequest(pDsiReq);
  1059. // remove the REQUEST refcount
  1060. DsiDereferenceConnection(pTcpConn);
  1061. DBGREFCOUNT(("DsiProcessData: REQUEST dec %lx (%d %d,%d)\n",
  1062. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1063. *pBytesAccepted = BytesIndicated;
  1064. return(STATUS_SUCCESS);
  1065. }
  1066. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1067. //
  1068. // were we using our own buffer to buffer data that came in pieces?
  1069. //
  1070. if (pTcpConn->con_State & TCPCONN_STATE_PARTIAL_DATA)
  1071. {
  1072. pTcpConn->con_State &= ~TCPCONN_STATE_PARTIAL_DATA;
  1073. }
  1074. //
  1075. // we weren't buffering, but using TCP's buffer: update counters
  1076. //
  1077. else
  1078. {
  1079. BytesConsumed += RequestLen;
  1080. pStreamPtr += RequestLen;
  1081. UnProcessedBytes -= RequestLen;
  1082. }
  1083. pTcpConn->con_RcvState = DSI_NEW_REQUEST;
  1084. ASSERT(pStreamPtr <= pBufferFromTcp+BytesIndicated);
  1085. break; // case DSI_HDR_COMPLETE:
  1086. default:
  1087. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1088. ("DsiProcessData: and what state is this??\n"));
  1089. ASSERT(0);
  1090. break;
  1091. } // switch (pTcpConn->con_RcvState)
  1092. //
  1093. // If there are more bytes yet to be processed, or if TCP has more
  1094. // bytes that we need to retrieve, we go back into the loop
  1095. //
  1096. if ((UnProcessedBytes > 0) || (fTCPHasMore))
  1097. {
  1098. fSomeMoreProcessing = TRUE;
  1099. }
  1100. } // while (fSomeMoreProcessing)
  1101. //
  1102. // if no bytes were indicated (if we came here not via TCP) then, we shouldn't
  1103. // have consumed anything!
  1104. //
  1105. if (BytesIndicated == 0)
  1106. {
  1107. ASSERT(BytesConsumed == 0);
  1108. }
  1109. // did TCP call us? then update byte count
  1110. if (BytesIndicated)
  1111. {
  1112. pTcpConn->con_BytesWithTcp += (BytesAvailable - BytesConsumed);
  1113. }
  1114. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1115. ASSERT( UnProcessedBytes == 0 );
  1116. ASSERT( BytesConsumed == BytesIndicated );
  1117. *pBytesAccepted = BytesConsumed;
  1118. return(status);
  1119. DsiProcessData_ErrorExit:
  1120. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1121. ("DsiProcessData: executing Error path, aborting connection %lx\n",pTcpConn));
  1122. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1123. DsiAbortConnection(pTcpConn);
  1124. *pBytesAccepted = BytesIndicated;
  1125. return(STATUS_SUCCESS);
  1126. }
  1127. /*** DsiTcpRcvIrpCompletion
  1128. *
  1129. * This routine is called into by TCP when it has finished copying all the data
  1130. * into the irp we supplied.
  1131. *
  1132. * Parm IN: Unused - well, unused!
  1133. * pIrp - the irp that we had passed
  1134. * pContext - our context (i.e. pTcpConn)
  1135. *
  1136. * Returns: status of operation
  1137. *
  1138. */
  1139. NTSTATUS
  1140. DsiTcpRcvIrpCompletion(
  1141. IN PDEVICE_OBJECT Unused,
  1142. IN PIRP pIrp,
  1143. IN PVOID pContext
  1144. )
  1145. {
  1146. PDEVICE_OBJECT pDeviceObject;
  1147. PTCPCONN pTcpConn;
  1148. PDSIREQ pDsiReq=NULL;
  1149. KIRQL OldIrql;
  1150. PMDL pMdl;
  1151. PMDL pOrgMdl;
  1152. PMDL pPrevPartialMdl;
  1153. PMDL pNewPartialMdl;
  1154. NTSTATUS status;
  1155. DWORD BytesTaken;
  1156. DWORD BytesThisTime;
  1157. DWORD BytesAvailable;
  1158. PIRP pIrpToPost=NULL;
  1159. DWORD BytesNeeded;
  1160. DWORD BytesSoFar;
  1161. pTcpConn = (PTCPCONN)pContext;
  1162. ASSERT(VALID_TCPCONN(pTcpConn));
  1163. ASSERT(pIrp == pTcpConn->con_pRcvIrp);
  1164. pMdl = pIrp->MdlAddress;
  1165. pPrevPartialMdl = (pMdl->MdlFlags & MDL_PARTIAL) ? pMdl : NULL;
  1166. status = pIrp->IoStatus.Status;
  1167. // if the receive failed, not much can be done with this connection!
  1168. if (!NT_SUCCESS(status))
  1169. {
  1170. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1171. ("DsiTcpRcvIrpCompletion: irp %lx failed %lx on %lx!\n",pIrp,status,pTcpConn));
  1172. goto DsiTcpRcvIrp_Completed;
  1173. }
  1174. pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
  1175. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1176. if (pTcpConn->con_State & (TCPCONN_STATE_CLOSING | TCPCONN_STATE_CLEANED_UP))
  1177. {
  1178. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1179. ("DsiTcpRcvIrpCompletion: conn %lx going away, ignoring date\n",pTcpConn));
  1180. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1181. goto DsiTcpRcvIrp_Completed;
  1182. }
  1183. ASSERT(pTcpConn->con_State & TCPCONN_STATE_TCP_HAS_IRP);
  1184. BytesThisTime = (DWORD)(pIrp->IoStatus.Information);
  1185. pDsiReq = pTcpConn->con_pDsiReq;
  1186. ASSERT(pDsiReq != NULL);
  1187. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  1188. switch (pTcpConn->con_RcvState)
  1189. {
  1190. case DSI_PARTIAL_COMMAND:
  1191. case DSI_PARTIAL_HEADER:
  1192. pDsiReq->dsi_PartialBufSize += BytesThisTime;
  1193. BytesSoFar = pDsiReq->dsi_PartialBufSize;
  1194. ASSERT(BytesSoFar <= pDsiReq->dsi_RequestLen);
  1195. BytesNeeded = (pDsiReq->dsi_RequestLen - BytesSoFar);
  1196. pOrgMdl = pDsiReq->dsi_pDsiAllocedMdl;
  1197. break;
  1198. case DSI_PARTIAL_WRITE:
  1199. pDsiReq->dsi_PartialWriteSize += BytesThisTime;
  1200. BytesSoFar = pDsiReq->dsi_PartialWriteSize;
  1201. ASSERT(BytesSoFar <= pDsiReq->dsi_WriteLen);
  1202. BytesNeeded = (pDsiReq->dsi_WriteLen - BytesSoFar);
  1203. pOrgMdl = pDsiReq->dsi_AfpRequest.rq_WriteMdl;
  1204. break;
  1205. default:
  1206. ASSERT(0);
  1207. break;
  1208. }
  1209. ASSERT((BytesSoFar+BytesNeeded) == AfpMdlChainSize(pOrgMdl));
  1210. if (pPrevPartialMdl == pOrgMdl)
  1211. {
  1212. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1213. ("DsiTcpRcvIrpCompletion: PrevPartial same as Org Mdl = %lx\n",pOrgMdl));
  1214. pPrevPartialMdl = NULL;
  1215. }
  1216. //
  1217. // update the count of how many bytes TCP has that we still need to retrieve.
  1218. // It's possible for TCP to return more bytes in this irp (BytesThisTime) than
  1219. // what we thought TCP had with it, because more stuff could have come on the wire
  1220. //
  1221. if (BytesThisTime > pTcpConn->con_BytesWithTcp)
  1222. {
  1223. pTcpConn->con_BytesWithTcp = 0;
  1224. }
  1225. else
  1226. {
  1227. pTcpConn->con_BytesWithTcp -= BytesThisTime;
  1228. }
  1229. BytesAvailable = pTcpConn->con_BytesWithTcp;
  1230. //
  1231. // if we still need more bytes to satisfy this request, we need to pass the irp
  1232. // back to TCP. We must first get a partial Mdl describing the new offset though
  1233. //
  1234. if (BytesNeeded > 0)
  1235. {
  1236. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1237. // free up previously allocated partial mdl, if any
  1238. if (pPrevPartialMdl)
  1239. {
  1240. ASSERT(pPrevPartialMdl != pOrgMdl);
  1241. IoFreeMdl(pPrevPartialMdl);
  1242. AFP_DBG_DEC_COUNT(AfpDbgMdlsAlloced);
  1243. pNewPartialMdl = NULL;
  1244. }
  1245. pNewPartialMdl = DsiMakePartialMdl(pOrgMdl, BytesSoFar);
  1246. if (pNewPartialMdl == NULL)
  1247. {
  1248. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1249. ("DsiTcpRcvIrpCompletion: couldn't get partial mdl\n"));
  1250. status = STATUS_INSUFFICIENT_RESOURCES;
  1251. goto DsiTcpRcvIrp_Completed;
  1252. }
  1253. TdiBuildReceive(pIrp,
  1254. pDeviceObject,
  1255. pTcpConn->con_pFileObject,
  1256. DsiTcpRcvIrpCompletion,
  1257. (PVOID)pTcpConn,
  1258. pNewPartialMdl,
  1259. TDI_RECEIVE_NORMAL,
  1260. BytesNeeded);
  1261. IoCallDriver(pDeviceObject,pIrp);
  1262. return(STATUS_MORE_PROCESSING_REQUIRED);
  1263. }
  1264. pTcpConn->con_State &= ~TCPCONN_STATE_TCP_HAS_IRP;
  1265. pTcpConn->con_pRcvIrp = NULL;
  1266. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1267. status = STATUS_SUCCESS;
  1268. DsiTcpRcvIrp_Completed:
  1269. // free up previously allocated partial mdl, if any
  1270. if (pPrevPartialMdl)
  1271. {
  1272. ASSERT(pPrevPartialMdl != pOrgMdl);
  1273. IoFreeMdl(pPrevPartialMdl);
  1274. AFP_DBG_DEC_COUNT(AfpDbgMdlsAlloced);
  1275. }
  1276. // if DSI had allocated Mdl, free it here
  1277. if (pDsiReq && pDsiReq->dsi_pDsiAllocedMdl)
  1278. {
  1279. AfpFreeMdl(pDsiReq->dsi_pDsiAllocedMdl);
  1280. pDsiReq->dsi_pDsiAllocedMdl = NULL;
  1281. }
  1282. // and, say good bye to that irp
  1283. AfpFreeIrp(pIrp);
  1284. //
  1285. // if the irp completed normally (most common case) then we need to call
  1286. // our processing loop so state is updated, Afp is informed (if needed) etc.
  1287. // also, if there are more bytes with TCP, we need to post an irp to get them
  1288. //
  1289. if (NT_SUCCESS(status))
  1290. {
  1291. status = DsiProcessData(pTcpConn,
  1292. 0,
  1293. BytesAvailable,
  1294. NULL,
  1295. &BytesTaken,
  1296. &pIrpToPost);
  1297. //
  1298. // does TCP have more data? then we have an irp to post to TCP
  1299. //
  1300. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  1301. {
  1302. ASSERT(pIrpToPost != NULL);
  1303. IoSkipCurrentIrpStackLocation(pIrpToPost);
  1304. IoCallDriver(pDeviceObject,pIrpToPost);
  1305. //
  1306. // remove the TcpIRP refcount since the original irp, pIrp completed
  1307. // The newer irp, pIrpToPost, will have upped refcount and will decrement
  1308. // when it completes
  1309. //
  1310. DsiDereferenceConnection(pTcpConn);
  1311. DBGREFCOUNT(("DsiTcpRcvIrpCompletion: TcpIRP dec %lx (%d %d,%d)\n",
  1312. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1313. return(STATUS_MORE_PROCESSING_REQUIRED);
  1314. }
  1315. //
  1316. // if DsiProcessData returns this errorcode, it's to tell TCP that it will
  1317. // give an irp later. It's not an error, so change it to success
  1318. //
  1319. else if (status == STATUS_DATA_NOT_ACCEPTED)
  1320. {
  1321. status = STATUS_SUCCESS;
  1322. }
  1323. }
  1324. if (!NT_SUCCESS(status))
  1325. {
  1326. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1327. ("DsiTcpRcvIrpCompletion: aborting %lx because status = %lx!\n",
  1328. pTcpConn, status));
  1329. DsiAbortConnection(pTcpConn);
  1330. }
  1331. // remove the TcpIRP refcount now that the irp completed
  1332. DsiDereferenceConnection(pTcpConn);
  1333. DBGREFCOUNT(("DsiTcpRcvIrpCompletion: TcpIRP dec %lx (%d %d,%d)\n",
  1334. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1335. return(STATUS_MORE_PROCESSING_REQUIRED);
  1336. }
  1337. /*** DsiExecuteCommand
  1338. *
  1339. * This routine looks at what DSI command has come from the client, and takes
  1340. * appropriate. If adequate data is not yet available to take action, it
  1341. * marks the state appropritely and returns.
  1342. *
  1343. * Parm IN: pTcpConn - the connection object
  1344. * pDsiReq - the DSI request object
  1345. *
  1346. * Returns: status of operation
  1347. *
  1348. */
  1349. NTSTATUS
  1350. DsiExecuteCommand(
  1351. IN PTCPCONN pTcpConn,
  1352. IN PDSIREQ pDsiReq
  1353. )
  1354. {
  1355. NTSTATUS status=STATUS_SUCCESS;
  1356. KIRQL OldIrql;
  1357. BOOLEAN fWeIniatedClose=FALSE;
  1358. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  1359. // we don't need to hold a lock here: it's not essential to be accurate
  1360. if (pDsiReq->dsi_Command != DSI_COMMAND_TICKLE)
  1361. {
  1362. pTcpConn->con_LastHeard = AfpSecondsSinceEpoch;
  1363. }
  1364. //
  1365. // see what command it is, and do the needful
  1366. //
  1367. switch (pDsiReq->dsi_Command)
  1368. {
  1369. case DSI_COMMAND_COMMAND:
  1370. case DSI_COMMAND_WRITE:
  1371. //
  1372. // make sure the guy has opened AFP session before we hand this over..
  1373. //
  1374. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1375. if (!(pTcpConn->con_State & TCPCONN_STATE_NOTIFY_AFP))
  1376. {
  1377. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1378. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1379. ("DsiExecuteCommand: must do OpenSession first! Disconnecting..\n"));
  1380. status = STATUS_UNSUCCESSFUL;
  1381. break;
  1382. }
  1383. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1384. // ok, hand over the request to AFP (AfpUnmarshall.. expects DPC)
  1385. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  1386. status = AfpCB_RequestNotify(STATUS_SUCCESS,
  1387. pTcpConn->con_pSda,
  1388. &pDsiReq->dsi_AfpRequest);
  1389. KeLowerIrql(OldIrql);
  1390. if (!NT_SUCCESS(status))
  1391. {
  1392. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1393. ("DsiExecuteCommand: AfpCB_RequestNotify failed %lx\n",status));
  1394. }
  1395. break;
  1396. case DSI_COMMAND_GETSTATUS:
  1397. status = DsiSendStatus(pTcpConn, pDsiReq);
  1398. if (!NT_SUCCESS(status))
  1399. {
  1400. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1401. ("DsiExecuteCommand: DsiSendStatus failed %lx\n",status));
  1402. }
  1403. break;
  1404. case DSI_COMMAND_CLOSESESSION:
  1405. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1406. fWeIniatedClose = (pDsiReq->dsi_Flags == DSI_REPLY);
  1407. pTcpConn->con_State |= TCPCONN_STATE_CLOSING;
  1408. pTcpConn->con_State |= TCPCONN_STATE_RCVD_REMOTE_CLOSE;
  1409. if (fWeIniatedClose)
  1410. {
  1411. RemoveEntryList(&pDsiReq->dsi_Linkage);
  1412. InitializeListHead(&pDsiReq->dsi_Linkage);
  1413. }
  1414. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1415. //
  1416. // if we initiated the CloseSession, then what we just got is the
  1417. // client's reponse. Done here: go ahead and terminate the connection.
  1418. //
  1419. if (fWeIniatedClose)
  1420. {
  1421. DsiFreeRequest(pDsiReq);
  1422. // remove the REQUEST refcount
  1423. DsiDereferenceConnection(pTcpConn);
  1424. DBGREFCOUNT(("DsiExecuteCommand: REQUEST dec %lx (%d %d,%d)\n",
  1425. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1426. DsiTerminateConnection(pTcpConn);
  1427. }
  1428. //
  1429. // remote client initiated the CloseSession. Tell AFP that the
  1430. // session is going away, and then send CloseSession response
  1431. //
  1432. else
  1433. {
  1434. DsiDisconnectWithAfp(pTcpConn, STATUS_REMOTE_DISCONNECT);
  1435. status = DsiSendDsiReply(pTcpConn, pDsiReq, STATUS_SUCCESS);
  1436. if (!NT_SUCCESS(status))
  1437. {
  1438. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1439. ("DsiExecuteCommand: send on CloseSess failed %lx\n",status));
  1440. }
  1441. }
  1442. break;
  1443. case DSI_COMMAND_OPENSESSION:
  1444. // see if AFP will accept this session request
  1445. status = DsiOpenSession(pTcpConn, pDsiReq);
  1446. if (!NT_SUCCESS(status))
  1447. {
  1448. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1449. ("DsiExecuteCommand: DsiOpenSession failed %lx\n",status));
  1450. }
  1451. DsiSendDsiReply(pTcpConn, pDsiReq, status);
  1452. status = STATUS_SUCCESS;
  1453. break;
  1454. //
  1455. // we got a tickle, or a response to our Attention.
  1456. // Just free up this request.
  1457. // If we get an unrecognized command, we just tear the connection down!
  1458. //
  1459. case DSI_COMMAND_TICKLE:
  1460. case DSI_COMMAND_ATTENTION:
  1461. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1462. RemoveEntryList(&pDsiReq->dsi_Linkage);
  1463. InitializeListHead(&pDsiReq->dsi_Linkage);
  1464. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1465. DsiFreeRequest(pDsiReq);
  1466. // remove the REQUEST refcount
  1467. DsiDereferenceConnection(pTcpConn);
  1468. DBGREFCOUNT(("DsiExecuteCommand: REQUEST dec %lx (%d %d,%d)\n",
  1469. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1470. break;
  1471. default:
  1472. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1473. ("DsiExecuteCommand: unknown command %d\n",pDsiReq->dsi_Command));
  1474. status = STATUS_UNSUCCESSFUL;
  1475. break;
  1476. }
  1477. return(status);
  1478. }
  1479. /*** DsiOpenSession
  1480. *
  1481. * This routine responds to an OpenSession request from the client, after
  1482. * notifying AFP and making sure that AFP wants to accept this connection
  1483. *
  1484. * Parm IN: pTcpConn - the connection object
  1485. * pDsiReq - the DSI request object
  1486. *
  1487. * Returns: status of operation
  1488. *
  1489. */
  1490. NTSTATUS
  1491. DsiOpenSession(
  1492. IN PTCPCONN pTcpConn,
  1493. IN PDSIREQ pDsiReq
  1494. )
  1495. {
  1496. KIRQL OldIrql;
  1497. PSDA pSda;
  1498. PBYTE pOptions;
  1499. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  1500. pSda = AfpCB_SessionNotify(pTcpConn, TRUE);
  1501. if (pSda == NULL)
  1502. {
  1503. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1504. ("DsiOpenSession: AfpCB_SessionNotify failed!\n"));
  1505. return(STATUS_INSUFFICIENT_RESOURCES);
  1506. }
  1507. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1508. pTcpConn->con_pSda = pSda;
  1509. pTcpConn->con_State |= TCPCONN_STATE_AFP_ATTACHED;
  1510. // from here on, if we disconnect, we must tell AFP
  1511. pTcpConn->con_State |= TCPCONN_STATE_NOTIFY_AFP;
  1512. // put AFP refcount, to be removed when AFP closes the session
  1513. pTcpConn->con_RefCount++;
  1514. DBGREFCOUNT(("DsiOpenSession: AFP inc %lx (%d %d,%d)\n",
  1515. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1516. //
  1517. // parse any options that might have arrived with the OpenSession command
  1518. // Currently, the only option that we can get from the client is the largest
  1519. // attention packet it can receive from us.
  1520. //
  1521. if (pDsiReq->dsi_RequestLen > 0)
  1522. {
  1523. // currently, this can only be 6 bytes
  1524. ASSERT(pDsiReq->dsi_RequestLen == 6);
  1525. pOptions = pDsiReq->dsi_AfpRequest.rq_RequestBuf;
  1526. ASSERT(pOptions[0] == 0x01);
  1527. ASSERT(pOptions[1] == 4);
  1528. GETDWORD2DWORD(&pTcpConn->con_MaxAttnPktSize, &pOptions[2]);
  1529. }
  1530. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1531. return(STATUS_SUCCESS);
  1532. }
  1533. /*** DsiSendDsiRequest
  1534. *
  1535. * This routine sends a request to the client. The only requests that originate
  1536. * from the server are CloseSession, Tickle and Attention
  1537. *
  1538. * Parm IN: pTcpConn - the connection object
  1539. * SendLen - how many bytes we are sending
  1540. * AttentionWord - if this is Attention request, the 2 bytes
  1541. * AttentionContext - context, if this is Attention request
  1542. * Command - which one is it: Close, Tickle or Attention
  1543. *
  1544. * Returns: status of operation
  1545. *
  1546. */
  1547. NTSTATUS
  1548. DsiSendDsiRequest(
  1549. IN PTCPCONN pTcpConn,
  1550. IN DWORD DataLen,
  1551. IN USHORT AttentionWord,
  1552. IN PVOID AttentionContext,
  1553. IN BYTE Command
  1554. )
  1555. {
  1556. NTSTATUS status;
  1557. KIRQL OldIrql;
  1558. PDSIREQ pDsiReq=NULL;
  1559. DWORD SendLen;
  1560. PBYTE pPacket;
  1561. PMDL pMdl;
  1562. pDsiReq = DsiGetRequest();
  1563. if (pDsiReq == NULL)
  1564. {
  1565. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1566. ("DsiAfpSendAttention: DsiGetRequest failed\n"));
  1567. return(STATUS_INSUFFICIENT_RESOURCES);
  1568. }
  1569. pPacket = &pDsiReq->dsi_RespHeader[0];
  1570. SendLen = DataLen + DSI_HEADER_SIZE;
  1571. pMdl = AfpAllocMdl(pPacket, SendLen, NULL);
  1572. if (pMdl == NULL)
  1573. {
  1574. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1575. ("DsiAfpSendAttention: alloc mdl failed\n"));
  1576. DsiFreeRequest(pDsiReq);
  1577. return(STATUS_INSUFFICIENT_RESOURCES);
  1578. }
  1579. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  1580. pDsiReq->dsi_RequestID = pTcpConn->con_OutgoingReqId++;
  1581. InsertTailList(&pTcpConn->con_PendingReqs, &pDsiReq->dsi_Linkage);
  1582. // put a REQUEST refcount
  1583. pTcpConn->con_RefCount++;
  1584. DBGREFCOUNT(("DsiSendDsiRequest: REQUEST inc %lx (%d %d,%d)\n",
  1585. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1586. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  1587. pDsiReq->dsi_Signature = DSI_REQUEST_SIGNATURE;
  1588. pDsiReq->dsi_pTcpConn = pTcpConn;
  1589. pDsiReq->dsi_Command = Command;
  1590. pDsiReq->dsi_Flags = DSI_REQUEST;
  1591. pDsiReq->dsi_pDsiAllocedMdl = pMdl;
  1592. //
  1593. // form the DSI header
  1594. //
  1595. pPacket[DSI_OFFSET_FLAGS] = DSI_REQUEST;
  1596. pPacket[DSI_OFFSET_COMMAND] = Command;
  1597. PUTSHORT2SHORT(&pPacket[DSI_OFFSET_REQUESTID], pDsiReq->dsi_RequestID);
  1598. *(DWORD *)&pPacket[DSI_OFFSET_DATAOFFSET] = 0;
  1599. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_DATALEN], DataLen);
  1600. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_RESERVED], 0);
  1601. if (Command == DSI_COMMAND_ATTENTION)
  1602. {
  1603. PUTSHORT2SHORT(&pPacket[DSI_HEADER_SIZE], AttentionWord);
  1604. pDsiReq->dsi_AttnContext = AttentionContext;
  1605. }
  1606. status = DsiTdiSend(pTcpConn,
  1607. pMdl,
  1608. SendLen,
  1609. DsiSendCompletion,
  1610. pDsiReq);
  1611. if (!NT_SUCCESS(status))
  1612. {
  1613. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1614. ("DsiSendDsiRequest: DsiTdiSend failed %lx\n",status));
  1615. AfpFreeMdl(pMdl);
  1616. pDsiReq->dsi_pDsiAllocedMdl = NULL;
  1617. DsiSendCompletion(NULL, NULL, pDsiReq);
  1618. status = STATUS_PENDING;
  1619. }
  1620. return(status);
  1621. }
  1622. /*** DsiSendDsiReply
  1623. *
  1624. * This routine sends a reply to the client, in response to the client's
  1625. * DSI-level request (OpenSession, CloseSession, or Tickle)
  1626. *
  1627. * Parm IN: pTcpConn - the connection object
  1628. * pDsiReq - the DIS request (from client's)
  1629. *
  1630. * Returns: status of operation
  1631. *
  1632. */
  1633. NTSTATUS
  1634. DsiSendDsiReply(
  1635. IN PTCPCONN pTcpConn,
  1636. IN PDSIREQ pDsiReq,
  1637. IN NTSTATUS OpStatus
  1638. )
  1639. {
  1640. PBYTE pPacket;
  1641. PBYTE pOption;
  1642. PMDL pMdl;
  1643. DWORD OptionLen;
  1644. DWORD TotalLen;
  1645. NTSTATUS status=STATUS_SUCCESS;
  1646. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  1647. if (pDsiReq->dsi_Command == DSI_COMMAND_OPENSESSION)
  1648. {
  1649. OptionLen = DSI_OPENSESS_OPTION_LEN + DSI_OPTION_FIXED_LEN;
  1650. TotalLen = DSI_HEADER_SIZE + OptionLen;
  1651. }
  1652. else
  1653. {
  1654. ASSERT((pDsiReq->dsi_Command == DSI_COMMAND_CLOSESESSION) ||
  1655. (pDsiReq->dsi_Command == DSI_COMMAND_TICKLE));
  1656. TotalLen = DSI_HEADER_SIZE;
  1657. OptionLen = 0;
  1658. }
  1659. pPacket = &pDsiReq->dsi_RespHeader[0];
  1660. RtlZeroMemory(pPacket, TotalLen);
  1661. pPacket[DSI_OFFSET_FLAGS] = DSI_REPLY;
  1662. pPacket[DSI_OFFSET_COMMAND] = pDsiReq->dsi_Command;
  1663. PUTSHORT2SHORT(&pPacket[DSI_OFFSET_REQUESTID], pDsiReq->dsi_RequestID);
  1664. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_DATALEN], OptionLen);
  1665. //
  1666. // if this is an OpenSession packet, setup the optional fields
  1667. //
  1668. if (pDsiReq->dsi_Command == DSI_COMMAND_OPENSESSION)
  1669. {
  1670. pOption = &pPacket[DSI_HEADER_SIZE];
  1671. pOption[DSI_OFFSET_OPTION_TYPE] = DSI_OPTION_SRVREQ_QUANTUM;
  1672. pOption[DSI_OFFSET_OPTION_LENGTH] = DSI_OPENSESS_OPTION_LEN;
  1673. PUTDWORD2DWORD(&pOption[DSI_OFFSET_OPTION_OPTION],
  1674. DSI_SERVER_REQUEST_QUANTUM);
  1675. // if open session didn't go well, tell client the whole store
  1676. if (OpStatus == STATUS_INSUFFICIENT_RESOURCES)
  1677. {
  1678. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_ERROROFFSET], ASP_SERVER_BUSY);
  1679. }
  1680. }
  1681. //
  1682. // allocate an mdl
  1683. //
  1684. pMdl = AfpAllocMdl(pPacket, TotalLen, NULL);
  1685. if (pMdl == NULL)
  1686. {
  1687. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1688. ("DsiSendDsiReply: malloc failed!\n"));
  1689. status = STATUS_INSUFFICIENT_RESOURCES;
  1690. }
  1691. if (NT_SUCCESS(status))
  1692. {
  1693. status = DsiTdiSend(pTcpConn,
  1694. pMdl,
  1695. TotalLen,
  1696. DsiSendCompletion,
  1697. pDsiReq);
  1698. if (!NT_SUCCESS(status))
  1699. {
  1700. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1701. ("DsiSendDsiReply: DsiTdiSend failed %lx\n",status));
  1702. }
  1703. }
  1704. if (!NT_SUCCESS(status))
  1705. {
  1706. if (pMdl)
  1707. {
  1708. AfpFreeMdl(pMdl);
  1709. }
  1710. DsiSendCompletion(NULL, NULL, pDsiReq);
  1711. }
  1712. return(status);
  1713. }
  1714. /*** DsiSendStatus
  1715. *
  1716. * This routine responds to the GetStatus requst from the client.
  1717. * Basically, we simply copy the status buffer here and send it.
  1718. *
  1719. * Parm IN: pTcpConn - the connection object
  1720. * pDsiReq - the DIS request (from client's)
  1721. *
  1722. * Returns: status of operation
  1723. *
  1724. */
  1725. NTSTATUS
  1726. DsiSendStatus(
  1727. IN PTCPCONN pTcpConn,
  1728. IN PDSIREQ pDsiReq
  1729. )
  1730. {
  1731. NTSTATUS status=STATUS_SUCCESS;
  1732. PBYTE pPacket;
  1733. PMDL pMdl=NULL;
  1734. KIRQL OldIrql;
  1735. DWORD TotalLen;
  1736. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  1737. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  1738. if (DsiStatusBuffer != NULL)
  1739. {
  1740. TotalLen = DsiStatusBufferSize + DSI_HEADER_SIZE;
  1741. pPacket = AfpAllocNonPagedMemory(TotalLen);
  1742. if (pPacket != NULL)
  1743. {
  1744. //
  1745. // form the DSI header
  1746. //
  1747. pPacket[DSI_OFFSET_FLAGS] = DSI_REPLY;
  1748. pPacket[DSI_OFFSET_COMMAND] = pDsiReq->dsi_Command;
  1749. PUTSHORT2SHORT(&pPacket[DSI_OFFSET_REQUESTID], pDsiReq->dsi_RequestID);
  1750. *(DWORD *)&pPacket[DSI_OFFSET_DATAOFFSET] = 0;
  1751. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_DATALEN], DsiStatusBufferSize);
  1752. PUTDWORD2DWORD(&pPacket[DSI_OFFSET_RESERVED], 0);
  1753. //
  1754. // copy the status buffer
  1755. //
  1756. RtlCopyMemory(pPacket + DSI_HEADER_SIZE,
  1757. DsiStatusBuffer,
  1758. DsiStatusBufferSize);
  1759. pMdl = AfpAllocMdl(pPacket, TotalLen, NULL);
  1760. if (pMdl == NULL)
  1761. {
  1762. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1763. ("DsiSendStatus: mdl alloc failed\n"));
  1764. AfpFreeMemory(pPacket);
  1765. status = STATUS_INSUFFICIENT_RESOURCES;
  1766. }
  1767. }
  1768. else
  1769. {
  1770. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1771. ("DsiSendStatus: malloc for GetStatus failed\n"));
  1772. status = STATUS_INSUFFICIENT_RESOURCES;
  1773. }
  1774. }
  1775. else
  1776. {
  1777. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1778. ("DsiSendStatus: DsiStatusBuffer is null, server didn't SetStatus?\n"));
  1779. status = STATUS_UNSUCCESSFUL;
  1780. }
  1781. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  1782. if (NT_SUCCESS(status))
  1783. {
  1784. status = DsiTdiSend(pTcpConn,
  1785. pMdl,
  1786. TotalLen,
  1787. DsiSendCompletion,
  1788. pDsiReq);
  1789. }
  1790. if (!NT_SUCCESS(status))
  1791. {
  1792. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1793. ("DsiSendStatus: DsiTdiSend failed %lx\n",status));
  1794. if (pMdl)
  1795. {
  1796. AfpFreeMdl(pMdl);
  1797. }
  1798. DsiSendCompletion(NULL, NULL, pDsiReq);
  1799. status = STATUS_PENDING;
  1800. }
  1801. return(status);
  1802. }
  1803. /*** DsiSendTickles
  1804. *
  1805. * This routine sends out a tickle from our end to every client that we haven't
  1806. * heard from in the last 30 seconds
  1807. *
  1808. * Parm IN: nothing
  1809. *
  1810. * Returns: status of operation
  1811. *
  1812. */
  1813. AFPSTATUS FASTCALL
  1814. DsiSendTickles(
  1815. IN PVOID pUnUsed
  1816. )
  1817. {
  1818. KIRQL OldIrql;
  1819. PLIST_ENTRY pList;
  1820. PTCPCONN pTcpConn;
  1821. AFPSTATUS status;
  1822. ASSERT(AfpServerBoundToTcp);
  1823. ASSERT(DsiTcpAdapter != NULL);
  1824. ACQUIRE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, &OldIrql);
  1825. // if adapter is shutting down, go back (and don't requeue)
  1826. if (DsiTcpAdapter->adp_State & TCPADPTR_STATE_CLOSING)
  1827. {
  1828. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1829. ("DsiSendTickles: adapter closing, so just returned\n"));
  1830. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  1831. return(AFP_ERR_NONE);
  1832. }
  1833. // put TickleTimer refcount: don't want it to go away till we're done here
  1834. DsiTcpAdapter->adp_RefCount++;
  1835. pList = DsiTcpAdapter->adp_ActiveConnHead.Flink;
  1836. while (pList != &DsiTcpAdapter->adp_ActiveConnHead)
  1837. {
  1838. pTcpConn = CONTAINING_RECORD(pList, TCPCONN, con_Linkage);
  1839. pList = pList->Flink;
  1840. ACQUIRE_SPIN_LOCK_AT_DPC(&pTcpConn->con_SpinLock);
  1841. // connection closing or tickles stopped on this connection? skip it
  1842. if (pTcpConn->con_State & (TCPCONN_STATE_CLOSING |
  1843. TCPCONN_STATE_TICKLES_STOPPED))
  1844. {
  1845. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  1846. ("DsiSendTickles: %lx closing or tickles stopped: skipping\n",pTcpConn));
  1847. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  1848. continue;
  1849. }
  1850. if (!(pTcpConn->con_State & TCPCONN_STATE_AFP_ATTACHED))
  1851. {
  1852. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1853. ("DsiSendTickles: %lx *** RACE CONDITION *** conn not setup yet\n",pTcpConn));
  1854. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  1855. continue;
  1856. }
  1857. // have we heard from the client recently for this puppy? if so, skip it
  1858. if ((AfpSecondsSinceEpoch - pTcpConn->con_LastHeard) < DSI_TICKLE_TIME_LIMIT)
  1859. {
  1860. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  1861. continue;
  1862. }
  1863. // reset this, so we don't keep sending
  1864. pTcpConn->con_LastHeard = AfpSecondsSinceEpoch;
  1865. // Put TICKLE refcount: make sure connection stays around till we're done!
  1866. pTcpConn->con_RefCount++;
  1867. DBGREFCOUNT(("DsiSendTickles: TICKLE inc %lx (%d %d,%d)\n",
  1868. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1869. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  1870. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  1871. DsiSendDsiRequest(pTcpConn, 0, 0, NULL, DSI_COMMAND_TICKLE);
  1872. ACQUIRE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, &OldIrql);
  1873. // since we released the lock, things could have changed: start over
  1874. pList = DsiTcpAdapter->adp_ActiveConnHead.Flink;
  1875. }
  1876. status = AFP_ERR_REQUEUE;
  1877. if (DsiTcpAdapter->adp_State & TCPADPTR_STATE_CLOSING)
  1878. {
  1879. status = AFP_ERR_NONE;
  1880. }
  1881. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  1882. // remove the TickleTimer refcount
  1883. DsiDereferenceAdapter(DsiTcpAdapter);
  1884. return(status);
  1885. }
  1886. /*** DsiValidateHeader
  1887. *
  1888. * This routine makes sure that the packet we just received looks good.
  1889. * i.e. whether the request id matches what we expect to receive, whether
  1890. * the command is valid, whether the Write length (if applicable) is what we
  1891. * negotiated (or less) etc.
  1892. *
  1893. * Parm IN: pTcpConn - the connection object
  1894. * pDsiReq - the DIS request (from client's)
  1895. *
  1896. * Returns: TRUE if the packet header is acceptable, FALSE otherwise
  1897. *
  1898. * NOTE: pTcpConn spinlock is held on entry
  1899. */
  1900. BOOLEAN
  1901. DsiValidateHeader(
  1902. IN PTCPCONN pTcpConn,
  1903. IN PDSIREQ pDsiReq
  1904. )
  1905. {
  1906. BOOLEAN fCheckIncomingReqId = TRUE;
  1907. //
  1908. // if this is the first packet we are receiving on this connection, note
  1909. // down what the client's starting request id is
  1910. //
  1911. if ((pDsiReq->dsi_Command == DSI_COMMAND_GETSTATUS) ||
  1912. (pDsiReq->dsi_Command == DSI_COMMAND_OPENSESSION))
  1913. {
  1914. if (pTcpConn->con_State & TCPCONN_STATE_AFP_ATTACHED)
  1915. {
  1916. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1917. ("DsiValidateHeader: session already going!\n"));
  1918. return(FALSE);
  1919. }
  1920. pTcpConn->con_NextReqIdToRcv =
  1921. (pDsiReq->dsi_RequestID == 0xFFFF)? 0 : (pDsiReq->dsi_RequestID+1);
  1922. fCheckIncomingReqId = FALSE;
  1923. }
  1924. else
  1925. {
  1926. if (!(pTcpConn->con_State & TCPCONN_STATE_AFP_ATTACHED))
  1927. {
  1928. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1929. ("DsiValidateHeader: command %d rcvd, but session not setup!\n",
  1930. pDsiReq->dsi_Command));
  1931. }
  1932. }
  1933. if (pDsiReq->dsi_Flags != DSI_REQUEST)
  1934. {
  1935. if (pDsiReq->dsi_Flags != DSI_REPLY)
  1936. {
  1937. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1938. ("DsiValidateHeader: Flags=%d, neither Request, nor reply\n",
  1939. pDsiReq->dsi_Flags));
  1940. return(FALSE);
  1941. }
  1942. //
  1943. // we expect REPLY from client only for two commands: anything else is bad
  1944. //
  1945. if ((pDsiReq->dsi_Command != DSI_COMMAND_CLOSESESSION) &&
  1946. (pDsiReq->dsi_Command != DSI_COMMAND_ATTENTION))
  1947. {
  1948. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1949. ("DsiValidateHeader: Flags=Reply, but cmd=%d\n",pDsiReq->dsi_Command));
  1950. return(FALSE);
  1951. }
  1952. fCheckIncomingReqId = FALSE;
  1953. }
  1954. //
  1955. // for all requests (except the first one), the RequestId must match what
  1956. // we expect. Otherwise, we just kill the connection!
  1957. //
  1958. if (fCheckIncomingReqId)
  1959. {
  1960. if (pDsiReq->dsi_RequestID != pTcpConn->con_NextReqIdToRcv)
  1961. {
  1962. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1963. ("DsiValidateHeader: ReqId mismatch (%ld vs. %ld)\n",
  1964. pDsiReq->dsi_RequestID,pTcpConn->con_NextReqIdToRcv));
  1965. return(FALSE);
  1966. }
  1967. if (pTcpConn->con_NextReqIdToRcv == 0xFFFF)
  1968. {
  1969. pTcpConn->con_NextReqIdToRcv = 0;
  1970. }
  1971. else
  1972. {
  1973. pTcpConn->con_NextReqIdToRcv++;
  1974. }
  1975. }
  1976. if (pDsiReq->dsi_RequestLen > DSI_SERVER_REQUEST_QUANTUM)
  1977. {
  1978. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1979. ("DsiValidateHeader: RequestLen too big %ld\n",pDsiReq->dsi_RequestLen));
  1980. return(FALSE);
  1981. }
  1982. if (pDsiReq->dsi_Command == DSI_COMMAND_WRITE)
  1983. {
  1984. if (pDsiReq->dsi_WriteLen > DSI_SERVER_REQUEST_QUANTUM)
  1985. {
  1986. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1987. ("DsiValidateHeader: WriteLen too big %ld\n",pDsiReq->dsi_WriteLen));
  1988. return(FALSE);
  1989. }
  1990. }
  1991. return(TRUE);
  1992. }
  1993. /*** DsiAfpReplyCompletion
  1994. *
  1995. * When AFP sends a reply to the client, DSI sends it out. When TCP completes
  1996. * that send, this routine gets called. We complete AFP's send at this point,
  1997. * and do other cleanup like releasing resources (if necessary)
  1998. *
  1999. * Parm IN: DeviceObject - not used
  2000. * pIrp - the irp that we sent out
  2001. * pContext - the DIS request (pDsiReq)
  2002. *
  2003. * Returns: status of operation
  2004. *
  2005. */
  2006. NTSTATUS
  2007. DsiAfpReplyCompletion(
  2008. IN PDEVICE_OBJECT DeviceObject,
  2009. IN PIRP pIrp,
  2010. IN PVOID pContext
  2011. )
  2012. {
  2013. PDSIREQ pDsiReq;
  2014. KIRQL OldIrql;
  2015. PMDL pMdl=NULL;
  2016. PTCPCONN pTcpConn;
  2017. PBYTE pPacket=NULL;
  2018. NTSTATUS status=STATUS_SUCCESS;
  2019. pDsiReq = (PDSIREQ)pContext;
  2020. ASSERT(pDsiReq->dsi_Signature == DSI_REQUEST_SIGNATURE);
  2021. pTcpConn = pDsiReq->dsi_pTcpConn;
  2022. ASSERT(VALID_TCPCONN(pTcpConn));
  2023. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  2024. RemoveEntryList(&pDsiReq->dsi_Linkage);
  2025. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  2026. if (pIrp)
  2027. {
  2028. status = pIrp->IoStatus.Status;
  2029. pMdl = pIrp->MdlAddress;
  2030. #if DBG
  2031. if (pMdl)
  2032. {
  2033. // put in a signature to say completion routine has runn on this puppy
  2034. pPacket = MmGetSystemAddressForMdlSafe(
  2035. pMdl,
  2036. NormalPagePriority);
  2037. if (pPacket != NULL)
  2038. {
  2039. *(DWORD *)pPacket = 0x11223344;
  2040. }
  2041. else
  2042. {
  2043. status = STATUS_INSUFFICIENT_RESOURCES;
  2044. }
  2045. }
  2046. #endif
  2047. // if this mdl was allocated by DSI, free it here
  2048. if (pDsiReq->dsi_pDsiAllocedMdl != NULL)
  2049. {
  2050. ASSERT(pDsiReq->dsi_pDsiAllocedMdl == pMdl);
  2051. ASSERT(pDsiReq->dsi_pDsiAllocedMdl->Next == pDsiReq->dsi_AfpRequest.rq_ReplyMdl);
  2052. pDsiReq->dsi_pDsiAllocedMdl->Next = NULL;
  2053. AfpFreeMdl(pDsiReq->dsi_pDsiAllocedMdl);
  2054. pDsiReq->dsi_pDsiAllocedMdl = NULL;
  2055. }
  2056. pIrp->MdlAddress = NULL;
  2057. AfpFreeIrp(pIrp);
  2058. }
  2059. else
  2060. {
  2061. status = STATUS_UNSUCCESSFUL;
  2062. }
  2063. AfpCB_ReplyCompletion(status, pTcpConn->con_pSda, &pDsiReq->dsi_AfpRequest);
  2064. DsiFreeRequest(pDsiReq);
  2065. // remove the REQUEST refcount
  2066. DsiDereferenceConnection(pTcpConn);
  2067. DBGREFCOUNT(("DsiAfpReplyCompletion: REQUEST dec %lx (%d %d,%d)\n",
  2068. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2069. return(STATUS_MORE_PROCESSING_REQUIRED);
  2070. }
  2071. /*** DsiSendCompletion
  2072. *
  2073. * When DSI sends a request (tickle, close session, attention) or reply
  2074. * (CloseSession, OpenSession) and when TCP completes that send, this routine
  2075. * gets called.
  2076. *
  2077. * Parm IN: DeviceObject - not used
  2078. * pIrp - the irp that we sent out
  2079. * pContext - the DIS request (pDsiReq)
  2080. *
  2081. * Returns: status of operation
  2082. *
  2083. */
  2084. NTSTATUS
  2085. DsiSendCompletion(
  2086. IN PDEVICE_OBJECT DeviceObject,
  2087. IN PIRP pIrp,
  2088. IN PVOID pContext
  2089. )
  2090. {
  2091. PDSIREQ pDsiReq;
  2092. KIRQL OldIrql;
  2093. PBYTE pPacket=NULL;
  2094. PBYTE pOption;
  2095. PMDL pMdl=NULL;
  2096. PTCPCONN pTcpConn;
  2097. NTSTATUS status=STATUS_SUCCESS;
  2098. BOOLEAN fMacHasAlreadySentClose=FALSE;
  2099. BOOLEAN fAfpIsAttached=TRUE;
  2100. pDsiReq = (PDSIREQ)pContext;
  2101. pTcpConn = pDsiReq->dsi_pTcpConn;
  2102. ASSERT(VALID_TCPCONN(pTcpConn));
  2103. if (pIrp)
  2104. {
  2105. status = pIrp->IoStatus.Status;
  2106. pMdl = pIrp->MdlAddress;
  2107. ASSERT(pMdl != NULL);
  2108. pPacket = MmGetSystemAddressForMdlSafe(
  2109. pMdl,
  2110. NormalPagePriority);
  2111. if (pPacket != NULL) {
  2112. if (pPacket != &pDsiReq->dsi_RespHeader[0])
  2113. {
  2114. AfpFreeMemory(pPacket);
  2115. }
  2116. }
  2117. AfpFreeMdl(pMdl);
  2118. pDsiReq->dsi_pDsiAllocedMdl = NULL;
  2119. AfpFreeIrp(pIrp);
  2120. }
  2121. else
  2122. {
  2123. status = STATUS_UNSUCCESSFUL;
  2124. }
  2125. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  2126. if (pTcpConn->con_State & TCPCONN_STATE_RCVD_REMOTE_CLOSE)
  2127. {
  2128. fMacHasAlreadySentClose = TRUE;
  2129. }
  2130. if (!(pTcpConn->con_State & TCPCONN_STATE_AFP_ATTACHED))
  2131. {
  2132. fAfpIsAttached = FALSE;
  2133. }
  2134. RemoveEntryList(&pDsiReq->dsi_Linkage);
  2135. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  2136. //
  2137. // was this an Attention? call afp's completion to say Attention was sent
  2138. //
  2139. if (pDsiReq->dsi_Command == DSI_COMMAND_ATTENTION)
  2140. {
  2141. AfpCB_AttnCompletion(pDsiReq->dsi_AttnContext);
  2142. }
  2143. // if this was a OpenSession reply and if it didn't go well, terminate the conn
  2144. else if ((pDsiReq->dsi_Command == DSI_COMMAND_OPENSESSION) && (!fAfpIsAttached))
  2145. {
  2146. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  2147. ("DsiSendCompletion: terminating conn since OpenSess didn't succeed %lx\n",pTcpConn));
  2148. DsiTerminateConnection(pTcpConn);
  2149. }
  2150. //
  2151. // if this was a CloseSession request and we have already received Mac's
  2152. // close, or if this was a GetStatus request, terminate the connection
  2153. //
  2154. else if (((pDsiReq->dsi_Command == DSI_COMMAND_CLOSESESSION) &&
  2155. (fMacHasAlreadySentClose)) ||
  2156. (pDsiReq->dsi_Command == DSI_COMMAND_GETSTATUS))
  2157. {
  2158. DsiTerminateConnection(pTcpConn);
  2159. }
  2160. //
  2161. // if this was a Tickle, remove that TICKLE refcount we had put before send
  2162. //
  2163. else if (pDsiReq->dsi_Command == DSI_COMMAND_TICKLE)
  2164. {
  2165. DsiDereferenceConnection(pTcpConn);
  2166. DBGREFCOUNT(("DsiSendCompletion: TICKLE dec %lx (%d %d,%d)\n",
  2167. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2168. }
  2169. //
  2170. // send failed? might as well abort!
  2171. //
  2172. if (!NT_SUCCESS(status))
  2173. {
  2174. if (!(pTcpConn->con_State & TCPCONN_STATE_CLEANED_UP))
  2175. {
  2176. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  2177. ("DsiSendCompletion: send failed %lx, so killing conection %lx\n",
  2178. status,pTcpConn));
  2179. }
  2180. DsiAbortConnection(pTcpConn);
  2181. }
  2182. // remove the REQUEST refcount
  2183. DsiDereferenceConnection(pTcpConn);
  2184. DBGREFCOUNT(("DsiSendCompletion: REQUEST dec %lx (%d %d,%d)\n",
  2185. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2186. DsiFreeRequest(pDsiReq);
  2187. return(STATUS_MORE_PROCESSING_REQUIRED);
  2188. }
  2189. /*** DsiAcceptConnectionCompletion
  2190. *
  2191. * When TCP completes the accept, this routine is called
  2192. *
  2193. * Parm IN: DeviceObject - unused
  2194. * pIrp - our irp that completed
  2195. * Context - our context (pTcpConn)
  2196. *
  2197. * Returns: status of operation
  2198. *
  2199. */
  2200. NTSTATUS
  2201. DsiAcceptConnectionCompletion(
  2202. IN PDEVICE_OBJECT DeviceObject,
  2203. IN PIRP pIrp,
  2204. IN PVOID Context
  2205. )
  2206. {
  2207. NTSTATUS status;
  2208. PTCPCONN pTcpConn;
  2209. KIRQL OldIrql;
  2210. BOOLEAN fMustDeref=FALSE;
  2211. pTcpConn = (PTCPCONN)Context;
  2212. ASSERT(VALID_TCPCONN(pTcpConn));
  2213. status = pIrp->IoStatus.Status;
  2214. // if the incoming connection failed to be setup right, go cleanup!
  2215. if (!NT_SUCCESS(status))
  2216. {
  2217. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  2218. ("DsiAcceptConnectionCompletion: connection failed %lx\n",status));
  2219. DsiAbortConnection(pTcpConn);
  2220. }
  2221. // this is our irp: free it
  2222. AfpFreeIrp(pIrp);
  2223. // remove the ACCEPT refcount
  2224. DsiDereferenceConnection(pTcpConn);
  2225. DBGREFCOUNT(("DsiAcceptConnectionCompletion: ACCEPT dec %lx (%d %d,%d)\n",
  2226. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2227. return(STATUS_MORE_PROCESSING_REQUIRED);
  2228. }
  2229. /*** DsiDisconnectWithTcp
  2230. *
  2231. * This routine passes an irp down to tcp, asking it to disconnect the connection
  2232. *
  2233. * Parm IN: pTcpConn - the connection object in question
  2234. * DiscFlag - how should the disconnect be, graceful or abortive
  2235. *
  2236. * Returns: result of operation
  2237. *
  2238. */
  2239. NTSTATUS
  2240. DsiDisconnectWithTcp(
  2241. IN PTCPCONN pTcpConn,
  2242. IN DWORD DiscFlag
  2243. )
  2244. {
  2245. PDEVICE_OBJECT pDeviceObject;
  2246. KIRQL OldIrql;
  2247. PIRP pIrp;
  2248. NTSTATUS status;
  2249. BOOLEAN fTcpAlreadyKnows=FALSE;
  2250. //
  2251. // find out if TCP still thinks the connection is up (basically watch out
  2252. // for a timing window where we send an irp down and tcp calls our disconnect
  2253. // handler: we want to deref only once in this case!)
  2254. //
  2255. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  2256. if (pTcpConn->con_State & TCPCONN_STATE_NOTIFY_TCP)
  2257. {
  2258. fTcpAlreadyKnows = FALSE;
  2259. pTcpConn->con_State &= ~TCPCONN_STATE_NOTIFY_TCP;
  2260. // put a DISCONNECT refcount, since we'll be sending an irp down
  2261. pTcpConn->con_RefCount++;
  2262. // mark that we initiated an abortive disconnect (we use this flag to avoid
  2263. // a race condition where we are doing a graceful close but the remote guy
  2264. // resets our connection)
  2265. if (DiscFlag == TDI_DISCONNECT_ABORT)
  2266. {
  2267. pTcpConn->con_State |= TCPCONN_STATE_ABORTIVE_DISCONNECT;
  2268. }
  2269. DBGREFCOUNT(("DsiDisconnectWithTcp: DISCONNECT inc %lx (%d %d,%d)\n",
  2270. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2271. }
  2272. else
  2273. {
  2274. fTcpAlreadyKnows = TRUE;
  2275. }
  2276. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  2277. if (fTcpAlreadyKnows)
  2278. {
  2279. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  2280. ("DsiDisconnectWithTcp: TCP already disconnected, no irp posted\n"));
  2281. return(STATUS_SUCCESS);
  2282. }
  2283. pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
  2284. if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
  2285. {
  2286. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  2287. ("DsiDisconnectWithTcp: AllocIrp failed\n"));
  2288. // remove that DISCONNECT refcount
  2289. DsiDereferenceConnection(pTcpConn);
  2290. DBGREFCOUNT(("DsiDisconnectWithTcp: DISCONNECT dec %lx (%d %d,%d)\n",
  2291. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2292. return(STATUS_INSUFFICIENT_RESOURCES);
  2293. }
  2294. pIrp->CancelRoutine = NULL;
  2295. TdiBuildDisconnect(
  2296. pIrp,
  2297. pDeviceObject,
  2298. pTcpConn->con_pFileObject,
  2299. DsiTcpDisconnectCompletion,
  2300. pTcpConn,
  2301. 0,
  2302. DiscFlag,
  2303. NULL,
  2304. NULL);
  2305. pIrp->MdlAddress = NULL;
  2306. status = IoCallDriver(pDeviceObject,pIrp);
  2307. if (!NT_SUCCESS(status))
  2308. {
  2309. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  2310. ("DsiDisconnectWithTcp: IoCallDriver failed %lx\n",status));
  2311. }
  2312. // if we are doing an abortive disconnect, tcp will not inform us anymore!
  2313. if (DiscFlag == TDI_DISCONNECT_ABORT)
  2314. {
  2315. // remove the TCP CLIENT-FIN refcount
  2316. DsiDereferenceConnection(pTcpConn);
  2317. DBGREFCOUNT(("DsiDisconnectWithTcp: CLIENT-FIN dec %lx (%d %d,%d)\n",
  2318. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2319. }
  2320. return(STATUS_PENDING);
  2321. }
  2322. /*** DsiDisconnectWithAfp
  2323. *
  2324. * This routine tells AFP that the connection is going away
  2325. *
  2326. * Parm IN: pTcpConn - the connection object in question
  2327. * Reason - why is the connection going away
  2328. *
  2329. * Returns: status of operation
  2330. *
  2331. */
  2332. NTSTATUS
  2333. DsiDisconnectWithAfp(
  2334. IN PTCPCONN pTcpConn,
  2335. IN NTSTATUS Reason
  2336. )
  2337. {
  2338. KIRQL OldIrql;
  2339. REQUEST Request;
  2340. BOOLEAN fAfpAlreadyKnows=FALSE;
  2341. RtlZeroMemory(&Request, sizeof(REQUEST));
  2342. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  2343. if (pTcpConn->con_State & TCPCONN_STATE_NOTIFY_AFP)
  2344. {
  2345. fAfpAlreadyKnows = FALSE;
  2346. pTcpConn->con_State &= ~TCPCONN_STATE_NOTIFY_AFP;
  2347. }
  2348. else
  2349. {
  2350. fAfpAlreadyKnows = TRUE;
  2351. }
  2352. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  2353. if (fAfpAlreadyKnows)
  2354. {
  2355. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  2356. ("DsiDisconnectWithAfp: AFP need not be told (again)\n"));
  2357. return(STATUS_SUCCESS);
  2358. }
  2359. //
  2360. // notify AFP that the connection is going away
  2361. //
  2362. Request.rq_RequestSize = (LONG)pTcpConn->con_DestIpAddr;
  2363. AfpCB_RequestNotify(Reason, pTcpConn->con_pSda, &Request);
  2364. return(STATUS_SUCCESS);
  2365. }
  2366. /*** DsiTcpDisconnectCompletion
  2367. *
  2368. * This routine is the completion routine when tcp completes our disconnect request
  2369. *
  2370. * Parm IN: DeviceObject - unused
  2371. * pIrp - our irp, to be freed
  2372. * Context - pTcpConn, our connection object
  2373. *
  2374. * Returns: result of operation
  2375. *
  2376. */
  2377. NTSTATUS
  2378. DsiTcpDisconnectCompletion(
  2379. IN PDEVICE_OBJECT DeviceObject,
  2380. IN PIRP pIrp,
  2381. IN PVOID Context
  2382. )
  2383. {
  2384. PTCPCONN pTcpConn;
  2385. KIRQL OldIrql;
  2386. NTSTATUS status=STATUS_SUCCESS;
  2387. pTcpConn = (PTCPCONN)Context;
  2388. ASSERT(VALID_TCPCONN(pTcpConn));
  2389. //
  2390. // tell AFP that the close completed
  2391. //
  2392. if (pTcpConn->con_pSda)
  2393. {
  2394. AfpCB_CloseCompletion(STATUS_SUCCESS, pTcpConn->con_pSda);
  2395. }
  2396. ACQUIRE_SPIN_LOCK(&DsiResourceLock, &OldIrql);
  2397. ASSERT(DsiNumTcpConnections > 0);
  2398. DsiNumTcpConnections--;
  2399. RELEASE_SPIN_LOCK(&DsiResourceLock, OldIrql);
  2400. // TCP is telling us it sent our FIN: remove the TCP SRVR-FIN refcount
  2401. DsiDereferenceConnection(pTcpConn);
  2402. DBGREFCOUNT(("DsiTcpDisconnectCompletion: SRVR-FIN dec %lx (%d %d,%d)\n",
  2403. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2404. if (pIrp != NULL)
  2405. {
  2406. status = pIrp->IoStatus.Status;
  2407. if (!NT_SUCCESS(status))
  2408. {
  2409. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  2410. ("DsiTcpDisconnectCompletion: status = %lx\n",status));
  2411. }
  2412. // remove the DISCONNECT refcount for completion of the irp
  2413. DsiDereferenceConnection(pTcpConn);
  2414. DBGREFCOUNT(("DsiTcpDisconnectCompletion: DISCONNECT dec %lx (%d %d,%d)\n",
  2415. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  2416. // it's ours: free it
  2417. AfpFreeIrp(pIrp);
  2418. }
  2419. return(STATUS_MORE_PROCESSING_REQUIRED);
  2420. }