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.

2777 lines
68 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. asp.c
  5. Abstract:
  6. This module implements the ASP protocol.
  7. Author:
  8. Jameel Hyder (jameelh@microsoft.com)
  9. Nikhil Kamkolkar (nikhilk@microsoft.com)
  10. Revision History:
  11. 30 Mar 1993 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #include <atalk.h>
  15. #pragma hdrstop
  16. #define FILENUM ASP
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(INIT, AtalkInitAspInitialize)
  19. #pragma alloc_text(PAGE, AtalkAspCreateAddress)
  20. #pragma alloc_text(PAGE_ASP, AtalkAspCloseAddress)
  21. #pragma alloc_text(PAGE_ASP, AtalkAspSetStatus)
  22. #pragma alloc_text(PAGE_ASP, AtalkAspListenControl)
  23. #pragma alloc_text(PAGE_ASP, AtalkAspCloseConnection)
  24. #pragma alloc_text(PAGE_ASP, AtalkAspFreeConnection)
  25. #pragma alloc_text(PAGE_ASP, AtalkAspCleanupConnection)
  26. #pragma alloc_text(PAGE_ASP, AtalkAspWriteContinue)
  27. #pragma alloc_text(PAGE_ASP, AtalkAspReply)
  28. #pragma alloc_text(PAGE_ASP, atalkAspPostWriteContinue)
  29. #pragma alloc_text(PAGE_ASP, AtalkAspSendAttention)
  30. #pragma alloc_text(PAGE_ASP, AtalkAspReferenceAddr)
  31. #pragma alloc_text(PAGE_ASP, atalkAspReferenceConnBySrcAddr)
  32. #pragma alloc_text(PAGE_ASP, AtalkAspDereferenceConn)
  33. #pragma alloc_text(PAGE_ASP, atalkAspSlsXHandler)
  34. #pragma alloc_text(PAGE_ASP, atalkAspSssXHandler)
  35. #pragma alloc_text(PAGE_ASP, atalkAspReplyRelease)
  36. #pragma alloc_text(PAGE_ASP, atalkAspWriteContinueResp)
  37. #pragma alloc_text(PAGE_ASP, atalkAspSendAttentionResp)
  38. #pragma alloc_text(PAGE_ASP, atalkAspSessionClose)
  39. #pragma alloc_text(PAGE_ASP, atalkAspReturnResp)
  40. #pragma alloc_text(PAGE_ASP, atalkAspRespComplete)
  41. #pragma alloc_text(PAGE_ASP, atalkAspCloseComplete)
  42. #endif
  43. /*
  44. * The model for ASP calls in this module is as follows:
  45. *
  46. * - For create calls (CreateAddress & CreateSession), a pointer to the created
  47. * object is returned. This structure is referenced for creation.
  48. * - For all other calls, it expects a referenced pointer to the object.
  49. */
  50. VOID
  51. AtalkInitAspInitialize(
  52. VOID
  53. )
  54. /*++
  55. Routine Description:
  56. Arguments:
  57. Return Value:
  58. --*/
  59. {
  60. LONG i;
  61. INITIALIZE_SPIN_LOCK(&atalkAspLock);
  62. for (i = 0; i < NUM_ASP_CONN_LISTS; i++)
  63. {
  64. AtalkTimerInitialize(&atalkAspConnMaint[i].ascm_SMTTimer,
  65. atalkAspSessionMaintenanceTimer,
  66. (SHORT)(ASP_SESSION_MAINTENANCE_TIMER - i*ASP_SESSION_TIMER_STAGGER));
  67. AtalkTimerScheduleEvent(&atalkAspConnMaint[i].ascm_SMTTimer);
  68. }
  69. }
  70. ATALK_ERROR
  71. AtalkAspCreateAddress(
  72. OUT PASP_ADDROBJ * ppAspAddr
  73. )
  74. /*++
  75. Routine Description:
  76. Create an ASP address object (aka listener). This object is associated with
  77. two seperate Atp sockets, one each for the Sls and the Sss. The Sls accepts
  78. the tickle, getstatus and opensession requests from the client end. The
  79. Sss accepts requests.
  80. Currently only the server side ASP is implemented and hence the ASP address
  81. object is only a listener.
  82. Arguments:
  83. Return Value:
  84. --*/
  85. {
  86. PASP_ADDROBJ pAspAddr = NULL;
  87. ATALK_ERROR Status;
  88. int i;
  89. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  90. ("AtalkAspCreateAddr: Entered\n"));
  91. do
  92. {
  93. // Allocate memory for the Asp address object
  94. if ((pAspAddr = AtalkAllocZeroedMemory(sizeof(ASP_ADDROBJ))) == NULL)
  95. {
  96. Status = ATALK_RESR_MEM;
  97. break;
  98. }
  99. // Initialize the Asp address object
  100. #if DBG
  101. pAspAddr->aspao_Signature = ASPAO_SIGNATURE;
  102. #endif
  103. INITIALIZE_SPIN_LOCK(&pAspAddr->aspao_Lock);
  104. // Refcounts for creation, Sls & Sss sockets and request handlers
  105. pAspAddr->aspao_RefCount = 1 + 2 + 2;
  106. pAspAddr->aspao_NextSessionId = 1;
  107. pAspAddr->aspao_EnableNewConnections = TRUE;
  108. // Create an Atp Socket on the port for the Sls
  109. Status = AtalkAtpOpenAddress(AtalkDefaultPort,
  110. 0,
  111. NULL,
  112. ATP_DEF_MAX_SINGLE_PKT_SIZE,
  113. ATP_DEF_SEND_USER_BYTES_ALL,
  114. NULL,
  115. TRUE, // CACHE this address
  116. &pAspAddr->aspao_pSlsAtpAddr);
  117. if (!ATALK_SUCCESS(Status))
  118. {
  119. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  120. ("AtalkAspCreateAddress: AtalkAtpOpenAddress for Sls failed %ld\n", Status));
  121. break;
  122. }
  123. // Set Request handler for the SLS to handle GetStatus, OpenSession and Tickle
  124. AtalkAtpSetReqHandler(pAspAddr->aspao_pSlsAtpAddr,
  125. atalkAspSlsXHandler,
  126. pAspAddr);
  127. // Create the Atp Socket on the port for the Sss
  128. Status = AtalkAtpOpenAddress(AtalkDefaultPort,
  129. 0,
  130. NULL,
  131. ATP_DEF_MAX_SINGLE_PKT_SIZE,
  132. ATP_DEF_SEND_USER_BYTES_ALL,
  133. NULL,
  134. TRUE, // CACHE this address
  135. &pAspAddr->aspao_pSssAtpAddr);
  136. if (!ATALK_SUCCESS(Status))
  137. {
  138. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  139. ("AtalkAspCreateAddress: AtalkAtpOpenAddress for Sss failed %ld\n", Status));
  140. break;
  141. }
  142. // Set Request handler for the SSS to handle Cmd/Write/Close
  143. AtalkAtpSetReqHandler(pAspAddr->aspao_pSssAtpAddr,
  144. atalkAspSssXHandler,
  145. pAspAddr);
  146. } while (FALSE);
  147. if (!ATALK_SUCCESS(Status))
  148. {
  149. if (pAspAddr != NULL)
  150. {
  151. if (pAspAddr->aspao_pSlsAtpAddr != NULL)
  152. {
  153. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  154. ("AtalkAspCreateAddress: Closing SLS Atp Address %lx\n",
  155. pAspAddr->aspao_pSlsAtpAddr));
  156. AtalkAtpCloseAddress(pAspAddr->aspao_pSlsAtpAddr, NULL, NULL);
  157. }
  158. if (pAspAddr->aspao_pSssAtpAddr != NULL)
  159. {
  160. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  161. ("AtalkAspCreateAddress: Closing SSS Atp Address %lx\n",
  162. pAspAddr->aspao_pSssAtpAddr));
  163. AtalkAtpCloseAddress(pAspAddr->aspao_pSssAtpAddr, NULL, NULL);
  164. }
  165. AtalkFreeMemory(pAspAddr);
  166. }
  167. }
  168. else
  169. {
  170. *ppAspAddr = pAspAddr;
  171. }
  172. return Status;
  173. }
  174. ATALK_ERROR
  175. AtalkAspCloseAddress(
  176. IN PASP_ADDROBJ pAspAddr,
  177. IN GENERIC_COMPLETION CompletionRoutine,
  178. IN PVOID CloseContext
  179. )
  180. /*++
  181. Routine Description:
  182. Arguments:
  183. Return Value:
  184. --*/
  185. {
  186. PASP_CONNOBJ pAspConn;
  187. KIRQL OldIrql;
  188. int i;
  189. ATALK_ERROR Status = ATALK_PENDING;
  190. PBYTE pStatusBuf;
  191. ASSERT(VALID_ASPAO(pAspAddr));
  192. ASSERT(pAspAddr->aspao_RefCount > 1);
  193. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  194. ("AtalkAspCloseAddr: Entered for Addr %lx\n", pAspAddr));
  195. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  196. pAspAddr->aspao_Flags |= ASPAO_CLOSING;
  197. pAspAddr->aspao_CloseCompletion = CompletionRoutine;
  198. pAspAddr->aspao_CloseContext = CloseContext;
  199. pStatusBuf = pAspAddr->aspao_pStatusBuf;
  200. pAspAddr->aspao_pStatusBuf = NULL;
  201. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  202. // Close down the atp sockets for Sls and Sss
  203. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  204. ("AtalkAspCloseAddress: Closing SLS Atp Address %lx\n",
  205. pAspAddr->aspao_pSlsAtpAddr));
  206. AtalkAtpCloseAddress(pAspAddr->aspao_pSlsAtpAddr,
  207. atalkAspCloseComplete,
  208. pAspAddr);
  209. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  210. ("AtalkAspCloseAddress: Closing SSS Atp Address %lx\n",
  211. pAspAddr->aspao_pSssAtpAddr));
  212. AtalkAtpCloseAddress(pAspAddr->aspao_pSssAtpAddr,
  213. atalkAspCloseComplete,
  214. pAspAddr);
  215. // Free the status buffer if any
  216. if (pStatusBuf != NULL)
  217. {
  218. AtalkFreeMemory(pStatusBuf);
  219. }
  220. // Shut down the active sessions now.
  221. for (i = 0; i < ASP_CONN_HASH_BUCKETS; i++)
  222. {
  223. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  224. pAspConn = pAspAddr->aspao_pSessions[i];
  225. while (pAspConn != NULL)
  226. {
  227. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  228. // if we have visited this guy, skip it
  229. if (pAspConn->aspco_Flags & ASPCO_SHUTDOWN)
  230. {
  231. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  232. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  233. ("AtalkAspCloseAddress: VISITED: skipping conn %lx Flags %lx RefCount %d\n",
  234. pAspConn,pAspConn->aspco_Flags,pAspConn->aspco_RefCount));
  235. // we still have the pAspAddr->aspao_Lock spinlock held!
  236. pAspConn = pAspConn->aspco_NextOverflow;
  237. continue;
  238. }
  239. pAspConn->aspco_Flags |= (ASPCO_LOCAL_CLOSE | ASPCO_SHUTDOWN);
  240. // Reference this since atalkAspSessionClose() expects it.
  241. pAspConn->aspco_RefCount ++;
  242. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  243. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  244. atalkAspSessionClose(pAspConn);
  245. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  246. }
  247. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  248. }
  249. ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
  250. // Let remaining cleanup happen during the Derefernce
  251. AtalkAspDereferenceAddr(pAspAddr); // Remove the creation reference
  252. return Status;
  253. }
  254. ATALK_ERROR
  255. AtalkAspBind(
  256. IN PASP_ADDROBJ pAspAddr,
  257. IN PASP_BIND_PARAMS pBindParms,
  258. IN PACTREQ pActReq
  259. )
  260. /*++
  261. Routine Description:
  262. Arguments:
  263. Return Value:
  264. --*/
  265. {
  266. KIRQL OldIrql;
  267. ASSERT (VALID_ASPAO(pAspAddr));
  268. // copy network addr
  269. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  270. pBindParms->pXportEntries->asp_AtalkAddr.Network =
  271. pAspAddr->aspao_pSlsAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Network;
  272. pBindParms->pXportEntries->asp_AtalkAddr.Node =
  273. pAspAddr->aspao_pSlsAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Node;
  274. pBindParms->pXportEntries->asp_AtalkAddr.Socket =
  275. pAspAddr->aspao_pSlsAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Socket;
  276. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  277. // Fill in our entry points into the client buffer
  278. pBindParms->pXportEntries->asp_AspCtxt = pAspAddr;
  279. pBindParms->pXportEntries->asp_SetStatus = AtalkAspSetStatus;
  280. pBindParms->pXportEntries->asp_CloseConn = AtalkAspCloseConnection;
  281. pBindParms->pXportEntries->asp_FreeConn = AtalkAspFreeConnection;
  282. pBindParms->pXportEntries->asp_ListenControl = AtalkAspListenControl;
  283. pBindParms->pXportEntries->asp_WriteContinue = AtalkAspWriteContinue;
  284. pBindParms->pXportEntries->asp_Reply = AtalkAspReply;
  285. pBindParms->pXportEntries->asp_SendAttention = AtalkAspSendAttention;
  286. // Get the clients entry points
  287. pAspAddr->aspao_ClientEntries = pBindParms->ClientEntries;
  288. // Call the completion routine before returning.
  289. (*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq);
  290. return ATALK_PENDING;
  291. }
  292. NTSTATUS
  293. AtalkAspSetStatus(
  294. IN PASP_ADDROBJ pAspAddr,
  295. IN PUCHAR pStatusBuf,
  296. IN USHORT StsBufSize
  297. )
  298. /*++
  299. Routine Description:
  300. Arguments:
  301. Return Value:
  302. --*/
  303. {
  304. KIRQL OldIrql;
  305. NTSTATUS Status = STATUS_SUCCESS;
  306. PUCHAR pOldBuf = NULL, pNewBuf = NULL;
  307. ASSERT(VALID_ASPAO(pAspAddr));
  308. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  309. ("AtalkAspSetStatus: Entered for Addr %lx\n", pAspAddr));
  310. do
  311. {
  312. if (pStatusBuf != NULL)
  313. {
  314. // Allocate a buffer and copy the contents of the passed in
  315. // buffer descriptor in it. Free an existing status buffer if one exists
  316. if (StsBufSize >= ASP_MAX_STATUS_SIZE)
  317. {
  318. Status = STATUS_BUFFER_TOO_SMALL;
  319. break;
  320. }
  321. if ((pNewBuf = AtalkAllocMemory(StsBufSize)) == NULL)
  322. {
  323. Status = STATUS_INSUFFICIENT_RESOURCES;
  324. break;
  325. }
  326. RtlCopyMemory(pNewBuf, pStatusBuf, StsBufSize);
  327. }
  328. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  329. if (pAspAddr->aspao_pStatusBuf != NULL)
  330. {
  331. ASSERT(pAspAddr->aspao_StsBufSize != 0);
  332. pOldBuf = pAspAddr->aspao_pStatusBuf;
  333. }
  334. pAspAddr->aspao_pStatusBuf = pNewBuf;
  335. pAspAddr->aspao_StsBufSize = StsBufSize;
  336. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  337. if (pOldBuf != NULL)
  338. AtalkFreeMemory(pOldBuf);
  339. } while (FALSE);
  340. return Status;
  341. }
  342. NTSTATUS FASTCALL
  343. AtalkAspListenControl(
  344. IN PASP_ADDROBJ pAspAddr,
  345. IN BOOLEAN Enable
  346. )
  347. /*++
  348. Routine Description:
  349. Arguments:
  350. Return Value:
  351. --*/
  352. {
  353. KIRQL OldIrql;
  354. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  355. if (AtalkAspReferenceAddr(pAspAddr))
  356. {
  357. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  358. pAspAddr->aspao_EnableNewConnections = Enable;
  359. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  360. AtalkAspDereferenceAddr(pAspAddr);
  361. Status = STATUS_SUCCESS;
  362. }
  363. return Status;
  364. }
  365. NTSTATUS
  366. AtalkAspCloseConnection(
  367. IN PASP_CONNOBJ pAspConn
  368. )
  369. /*++
  370. Routine Description:
  371. Shutdown a session.
  372. Arguments:
  373. Return Value:
  374. --*/
  375. {
  376. KIRQL OldIrql;
  377. BOOLEAN CompListen = FALSE;
  378. ASSERT(VALID_ASPCO(pAspConn));
  379. ASSERT(pAspConn->aspco_RefCount > 0);
  380. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  381. ("AtalkAspCloseConn: Entered for Conn %lx\n", pAspConn));
  382. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  383. ("AtalkCloseConnection: Close session from %d.%d for Session %d\n",
  384. pAspConn->aspco_WssRemoteAddr.ata_Network,
  385. pAspConn->aspco_WssRemoteAddr.ata_Node,
  386. pAspConn->aspco_SessionId));
  387. AtalkAspCleanupConnection(pAspConn);
  388. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  389. pAspConn->aspco_Flags |= (ASPCO_CLOSING | ASPCO_LOCAL_CLOSE);
  390. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  391. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  392. ("AtalkAspCloseConnection: Done for %lx (%ld)\n",
  393. pAspConn, pAspConn->aspco_RefCount));
  394. // Let remaining cleanup happen during the Derefernce
  395. AtalkAspDereferenceConn(pAspConn); // Remove the creation reference
  396. #ifdef PROFILING
  397. INTERLOCKED_DECREMENT_LONG( &AtalkStatistics.stat_CurAspSessions,
  398. &AtalkStatsLock.SpinLock);
  399. #endif
  400. return STATUS_PENDING;
  401. }
  402. NTSTATUS
  403. AtalkAspFreeConnection(
  404. IN PASP_CONNOBJ pAspConn
  405. )
  406. /*++
  407. Routine Description:
  408. Shutdown a session.
  409. Arguments:
  410. Return Value:
  411. --*/
  412. {
  413. return STATUS_SUCCESS;
  414. }
  415. ATALK_ERROR
  416. AtalkAspCleanupConnection(
  417. IN PASP_CONNOBJ pAspConn
  418. )
  419. /*++
  420. Routine Description:
  421. Cancel all I/O on this session. Complete pending replies and write
  422. continues with error.
  423. Arguments:
  424. Return Value:
  425. --*/
  426. {
  427. PASP_REQUEST pAspReq;
  428. PASP_ADDROBJ pAspAddr;
  429. ATALK_ERROR Status;
  430. KIRQL OldIrql;
  431. USHORT XactId;
  432. BYTE UserBytes[ATP_USERBYTES_SIZE];
  433. ATALK_ADDR RemoteAddr;
  434. BOOLEAN CancelTickle, AlreadyCleaning, fConnActive;
  435. ATALK_ERROR error;
  436. ASSERT(VALID_ASPCO(pAspConn));
  437. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  438. ("AtalkAspCleanupConnection: For %lx\n", pAspConn));
  439. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  440. CancelTickle = ((pAspConn->aspco_Flags & ASPCO_TICKLING) != 0);
  441. AlreadyCleaning = (pAspConn->aspco_Flags & ASPCO_CLEANING_UP) ? TRUE : FALSE;
  442. if (AlreadyCleaning)
  443. {
  444. pAspConn->aspco_Flags &= ~ASPCO_TICKLING;
  445. }
  446. fConnActive = (pAspConn->aspco_Flags & ASPCO_ACTIVE) ? TRUE : FALSE;
  447. pAspConn->aspco_Flags &= ~ASPCO_ACTIVE;
  448. pAspConn->aspco_Flags |= ASPCO_CLEANING_UP;
  449. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  450. if (AlreadyCleaning)
  451. return ATALK_NO_ERROR;
  452. pAspAddr = pAspConn->aspco_pAspAddr;
  453. ASSERT(VALID_ASPAO(pAspAddr));
  454. // Send a session close request, if this is an active connection
  455. if (fConnActive)
  456. {
  457. UserBytes[ASP_CMD_OFF] = ASP_CLOSE_SESSION;
  458. UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
  459. PUTSHORT2SHORT(UserBytes + ASP_ATTN_WORD_OFF, 0);
  460. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  461. ("AtalkAspCleanupConnection: Sending close req for %lx\n",
  462. pAspConn));
  463. Status = AtalkAtpPostReq(pAspAddr->aspao_pSssAtpAddr,
  464. &pAspConn->aspco_WssRemoteAddr,
  465. &XactId,
  466. ATP_REQ_REMOTE, // Close session request is ALO
  467. NULL,
  468. 0,
  469. UserBytes,
  470. NULL,
  471. 0,
  472. ATP_RETRIES_FOR_ASP,
  473. ATP_MAX_INTERVAL_FOR_ASP,
  474. THIRTY_SEC_TIMER,
  475. NULL,
  476. NULL);
  477. if (!ATALK_SUCCESS(Status))
  478. {
  479. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  480. ("AtalkAspCleanupConn: AtalkAtpPostReq %ld\n", Status));
  481. }
  482. }
  483. // Cancel tickle packets
  484. if (CancelTickle)
  485. {
  486. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  487. ("AtalkAspCleanupConnection: Cancel tickle for %lx\n", pAspConn));
  488. Status = AtalkAtpCancelReq(pAspAddr->aspao_pSlsAtpAddr,
  489. pAspConn->aspco_TickleXactId,
  490. &pAspConn->aspco_WssRemoteAddr);
  491. if (!ATALK_SUCCESS(Status))
  492. {
  493. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  494. ("AtalkAspCleanupConn: AtalkAtpCancelReq %ld\n", Status));
  495. }
  496. }
  497. do
  498. {
  499. BOOLEAN CancelReply = FALSE;
  500. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  501. for (pAspReq = pAspConn->aspco_pActiveReqs;
  502. pAspReq != NULL;
  503. pAspReq = pAspReq->asprq_Next)
  504. {
  505. ASSERT (VALID_ASPRQ(pAspReq));
  506. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  507. ("AtalkAspCleanupConnection: Found req %lx (%lx) for %lx\n",
  508. pAspReq, pAspReq->asprq_Flags, pAspConn));
  509. CancelReply = FALSE;
  510. if ((pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_WRTCONT_CANCELLED)) == ASPRQ_WRTCONT)
  511. {
  512. pAspReq->asprq_Flags |= ASPRQ_WRTCONT_CANCELLED;
  513. RemoteAddr = pAspConn->aspco_WssRemoteAddr;
  514. break;
  515. }
  516. if ((pAspReq->asprq_Flags & (ASPRQ_REPLY | ASPRQ_REPLY_CANCELLED)) == ASPRQ_REPLY)
  517. {
  518. CancelReply = TRUE;
  519. pAspReq->asprq_Flags |= ASPRQ_REPLY_CANCELLED;
  520. break;
  521. }
  522. }
  523. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  524. if (pAspReq != NULL)
  525. {
  526. if (CancelReply)
  527. {
  528. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  529. ("AtalkAspCleanupConnection: Cancel reply for %lx, flag=%lx\n",
  530. pAspReq,pAspReq->asprq_Flags));
  531. error = AtalkAtpCancelResp(pAspReq->asprq_pAtpResp);
  532. if (!ATALK_SUCCESS(error))
  533. {
  534. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  535. ("AtalkAspCleanupConnection: AtalkAtpCancelResp failed %lx\n",error));
  536. }
  537. }
  538. else
  539. {
  540. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  541. ("AtalkAspCleanupConnection: Cancel wrtcont for %lx, flag=%lx\n",
  542. pAspReq,pAspReq->asprq_Flags));
  543. error = AtalkAtpCancelReq(pAspConn->aspco_pAspAddr->aspao_pSssAtpAddr,
  544. pAspReq->asprq_WCXactId,
  545. &RemoteAddr);
  546. if (!ATALK_SUCCESS(error))
  547. {
  548. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  549. ("AtalkAspCleanupConnection: AtalkAtpCancelReq failed %lx\n",error));
  550. }
  551. }
  552. }
  553. else
  554. {
  555. break;
  556. }
  557. } while (TRUE);
  558. return ATALK_NO_ERROR;
  559. }
  560. NTSTATUS FASTCALL
  561. AtalkAspWriteContinue(
  562. IN PREQUEST pRequest
  563. )
  564. /*++
  565. Routine Description:
  566. The response buffer is in the request itself.
  567. Arguments:
  568. Return Value:
  569. --*/
  570. {
  571. PASP_REQUEST pAspReq;
  572. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  573. ("AtalkAspWriteContinue: Entered with pRequest %lx\n", pRequest));
  574. pAspReq = CONTAINING_RECORD(pRequest, ASP_REQUEST, asprq_Request);
  575. ASSERT (VALID_ASPRQ(pAspReq));
  576. if (pRequest->rq_WriteMdl != NULL)
  577. {
  578. atalkAspPostWriteContinue(pAspReq);
  579. return(STATUS_SUCCESS);
  580. }
  581. else
  582. {
  583. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  584. ("AtalkAspWriteContinue: buffer alloc failed, completing write with error\n"));
  585. atalkAspWriteContinueResp(ATALK_RESR_MEM, pAspReq, NULL, NULL, 0, NULL);
  586. }
  587. return(STATUS_SUCCESS);
  588. }
  589. NTSTATUS FASTCALL
  590. AtalkAspReply(
  591. IN PREQUEST pRequest, // Pointer to request
  592. IN PBYTE pResultCode // Pointer to the 4-byte result
  593. )
  594. /*++
  595. Routine Description:
  596. The response buffer is in the request itself.
  597. Arguments:
  598. Return Value:
  599. --*/
  600. {
  601. PASP_REQUEST pAspReq, *ppAspReq;
  602. PASP_CONNOBJ pAspConn;
  603. PASP_ADDROBJ pAspAddr;
  604. ATALK_ERROR error;
  605. KIRQL OldIrql;
  606. USHORT ReplySize;
  607. pAspReq = CONTAINING_RECORD(pRequest, ASP_REQUEST, asprq_Request);
  608. ASSERT (VALID_ASPRQ(pAspReq));
  609. pAspConn = pAspReq->asprq_pAspConn;
  610. ASSERT(VALID_ASPCO(pAspConn));
  611. pAspAddr = pAspConn->aspco_pAspAddr;
  612. ASSERT(VALID_ASPAO(pAspAddr));
  613. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  614. ("AtalkAspReply: Entered for session %lx\n", pAspConn));
  615. ASSERT ((pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_REPLY)) == 0);
  616. do
  617. {
  618. // Find and de-queue this request from the list
  619. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  620. for (ppAspReq = &pAspConn->aspco_pActiveReqs;
  621. *ppAspReq != NULL;
  622. ppAspReq = &(*ppAspReq)->asprq_Next)
  623. {
  624. if (pAspReq == *ppAspReq)
  625. {
  626. *ppAspReq = pAspReq->asprq_Next;
  627. pAspConn->aspco_cReqsInProcess --;
  628. pAspReq->asprq_Flags |= ASPRQ_REPLY;
  629. break;
  630. }
  631. }
  632. ASSERT(*ppAspReq == pAspReq->asprq_Next);
  633. if (pAspConn->aspco_Flags & (ASPCO_CLEANING_UP |
  634. ASPCO_CLOSING |
  635. ASPCO_LOCAL_CLOSE |
  636. ASPCO_REMOTE_CLOSE))
  637. {
  638. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  639. ("AtalkAspReply: Session Closing - session %x\n", pAspConn->aspco_SessionId));
  640. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  641. pAspReq->asprq_Flags &= ~ASPRQ_REPLY;
  642. pAspReq->asprq_Flags |= ASPRQ_REPLY_ABORTED;
  643. error = ATALK_LOCAL_CLOSE;
  644. break;
  645. }
  646. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  647. ReplySize = (USHORT)AtalkSizeMdlChain(pAspReq->asprq_Request.rq_ReplyMdl);
  648. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  649. ("AtalkAspReply: Posting AtalkAtpPostResp for request %lx\n", pAspReq));
  650. error = AtalkAtpPostResp(pAspReq->asprq_pAtpResp,
  651. &pAspReq->asprq_RemoteAddr,
  652. pAspReq->asprq_Request.rq_ReplyMdl,
  653. ReplySize,
  654. pResultCode,
  655. atalkAspReplyRelease,
  656. pAspReq);
  657. if (!ATALK_SUCCESS(error))
  658. {
  659. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  660. ("AtalkAspReply: AtalkAtpPostResp %ld\n", error));
  661. }
  662. } while (FALSE);
  663. if (!ATALK_SUCCESS(error))
  664. {
  665. if (error != ATALK_ATP_RESP_TOOMANY)
  666. {
  667. atalkAspReplyRelease(error, pAspReq);
  668. }
  669. }
  670. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  671. ("AtalkAspReply: Completing request %lx, Status %ld\n",
  672. pAspReq, error));
  673. return STATUS_PENDING;
  674. }
  675. LOCAL ATALK_ERROR FASTCALL
  676. atalkAspPostWriteContinue(
  677. IN PASP_REQUEST pAspReq
  678. )
  679. /*++
  680. Routine Description:
  681. Arguments:
  682. Return Value:
  683. --*/
  684. {
  685. ATALK_ERROR error;
  686. PASP_CONNOBJ pAspConn;
  687. PAMDL pAMdl = NULL;
  688. BYTE UserBytes[ATP_USERBYTES_SIZE];
  689. USHORT RespSize;
  690. ASSERT (VALID_ASPRQ(pAspReq));
  691. pAspConn = pAspReq->asprq_pAspConn;
  692. ASSERT(VALID_ASPCO(pAspConn));
  693. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  694. ("atalkAspPostWriteContinue: Entered for session %lx\n", pAspConn));
  695. RespSize = (USHORT)AtalkSizeMdlChain(pAspReq->asprq_Request.rq_WriteMdl);
  696. ASSERT (RespSize <= ATP_MAX_TOTAL_RESPONSE_SIZE);
  697. if (RespSize > ATP_MAX_TOTAL_RESPONSE_SIZE)
  698. RespSize = ATP_MAX_TOTAL_RESPONSE_SIZE;
  699. ASSERT (!(pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_WRTCONT_CANCELLED)));
  700. pAspReq->asprq_Flags |= ASPRQ_WRTCONT;
  701. do
  702. {
  703. // We need to build an AMdl for two bytes of response which
  704. // indicates how much data we are expecting !!!
  705. if ((pAMdl = AtalkAllocAMdl(pAspReq->asprq_WrtContRespBuf,
  706. ASP_WRITE_DATA_SIZE)) == NULL)
  707. {
  708. error = ATALK_RESR_MEM;
  709. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  710. ("AtalkAspWriteContinue: AtalkAllocMdl failed for 2 bytes !!\n"));
  711. }
  712. else
  713. {
  714. PBYTE pWrtData;
  715. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  716. ("AtalkAspWriteContinue: Posting AtalkAtpPostReq for request %lx\n",
  717. pAspReq));
  718. pWrtData = AtalkGetAddressFromMdlSafe(pAMdl, NormalPagePriority);
  719. if (pWrtData == NULL)
  720. {
  721. if (pAMdl != NULL)
  722. {
  723. AtalkFreeAMdl(pAMdl);
  724. }
  725. error = ATALK_RESR_MEM;
  726. break;
  727. }
  728. UserBytes[ASP_CMD_OFF] = ASP_WRITE_DATA;
  729. UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
  730. PUTSHORT2SHORT(UserBytes+ASP_SEQUENCE_NUM_OFF, pAspReq->asprq_SeqNum);
  731. PUTSHORT2SHORT(pWrtData, RespSize);
  732. // Snapshot the current tick count. We use this to adjust the retry times on
  733. // write continue.
  734. pAspConn->aspco_RT.rt_New = AtalkGetCurrentTick();
  735. error = AtalkAtpPostReq(pAspConn->aspco_pAspAddr->aspao_pSssAtpAddr,
  736. &pAspConn->aspco_WssRemoteAddr,
  737. &pAspReq->asprq_WCXactId,
  738. ATP_REQ_EXACTLY_ONCE | ATP_REQ_REMOTE,
  739. pAMdl,
  740. ASP_WRITE_DATA_SIZE,
  741. UserBytes,
  742. pAspReq->asprq_Request.rq_WriteMdl,
  743. RespSize,
  744. ATP_INFINITE_RETRIES,
  745. pAspConn->aspco_RT.rt_Base,
  746. THIRTY_SEC_TIMER,
  747. atalkAspWriteContinueResp,
  748. pAspReq);
  749. if (!ATALK_SUCCESS(error))
  750. {
  751. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  752. ("AtalkAspWriteContinue: AtalkAtpPostReq %ld\n", error));
  753. }
  754. }
  755. if (!ATALK_SUCCESS(error))
  756. {
  757. if (pAMdl != NULL)
  758. AtalkFreeAMdl(pAMdl);
  759. }
  760. } while (FALSE);
  761. return error;
  762. }
  763. NTSTATUS
  764. AtalkAspSendAttention(
  765. IN PASP_CONNOBJ pAspConn,
  766. IN USHORT AttentionWord,
  767. IN PVOID pContext
  768. )
  769. /*++
  770. Routine Description:
  771. Arguments:
  772. Return Value:
  773. --*/
  774. {
  775. ATALK_ERROR error;
  776. NTSTATUS Status = STATUS_SUCCESS;
  777. KIRQL OldIrql;
  778. PAMDL pAMdl = NULL;
  779. BYTE UserBytes[ATP_USERBYTES_SIZE];
  780. USHORT XactId, RespSize = 16; // Some small number (see comment below)
  781. ASSERT(VALID_ASPCO(pAspConn));
  782. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  783. ("AtalkAspSendAttention: Entered for session %lx\n", pAspConn));
  784. // Reference by src addr here instead of by pointer since the former will
  785. // fail when the session is in one of the stages of death whereas the
  786. // latter will not. Also this assumes that it is called at dispatch so raise irql.
  787. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  788. pAspConn = atalkAspReferenceConnBySrcAddr(pAspConn->aspco_pAspAddr,
  789. &pAspConn->aspco_WssRemoteAddr,
  790. pAspConn->aspco_SessionId);
  791. KeLowerIrql(OldIrql);
  792. if (pAspConn == NULL)
  793. return STATUS_REQUEST_NOT_ACCEPTED;
  794. UserBytes[ASP_CMD_OFF] = ASP_ATTENTION;
  795. UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
  796. PUTSHORT2SHORT(UserBytes+ASP_ATTN_WORD_OFF, AttentionWord);
  797. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  798. ("AtalkAspSendAttention: Posting AtalkAtpPostReq for Conn %lx\n", pAspConn));
  799. // We need to build an AMdl for a dummy buffer to hold the response.
  800. // There is no real response but some clients fry their
  801. // machines if we don't !!! If we cannot allocate the mdl we we go
  802. // ahead anyway.
  803. if ((pAMdl = AtalkAllocAMdl(NULL, RespSize)) == NULL)
  804. {
  805. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  806. ("AtalkAspSendAttention: AtalkAllocMdl failed for dummy buffer !!\n"));
  807. RespSize = 0;
  808. }
  809. pAspConn->aspco_AttentionContext = pContext;
  810. error = AtalkAtpPostReq(pAspConn->aspco_pAspAddr->aspao_pSssAtpAddr,
  811. &pAspConn->aspco_WssRemoteAddr,
  812. &XactId,
  813. ATP_REQ_REMOTE, // SendAttention is ALO
  814. NULL,
  815. 0,
  816. UserBytes,
  817. pAMdl,
  818. RespSize,
  819. ATP_RETRIES_FOR_ASP,
  820. ATP_MAX_INTERVAL_FOR_ASP,
  821. THIRTY_SEC_TIMER,
  822. atalkAspSendAttentionResp,
  823. pAspConn);
  824. if (!ATALK_SUCCESS(error))
  825. {
  826. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  827. ("AtalkAspSendAttention: AtalkAtpPostReq %ld\n", Status));
  828. Status = AtalkErrorToNtStatus(error);
  829. atalkAspSendAttentionResp(error,
  830. pAspConn,
  831. NULL,
  832. pAMdl,
  833. RespSize,
  834. UserBytes);
  835. }
  836. return Status;
  837. }
  838. PASP_ADDROBJ FASTCALL
  839. AtalkAspReferenceAddr(
  840. IN PASP_ADDROBJ pAspAddr
  841. )
  842. /*++
  843. Routine Description:
  844. Arguments:
  845. Return Value:
  846. --*/
  847. {
  848. KIRQL OldIrql;
  849. PASP_ADDROBJ pRefAddr;
  850. ASSERT(VALID_ASPAO(pAspAddr));
  851. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  852. ("AtalkAspReferenceAddr: Addr %lx, PreCount %ld\n",
  853. pAspAddr, pAspAddr->aspao_RefCount));
  854. pRefAddr = pAspAddr;
  855. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  856. ASSERT(pAspAddr->aspao_RefCount > 1);
  857. if (pAspAddr->aspao_Flags & ASPAO_CLOSING)
  858. {
  859. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  860. ("AtalkAspReferenceAddr: Referencing closing object %lx!!\n",
  861. pAspAddr));
  862. pRefAddr = NULL;
  863. }
  864. else pAspAddr->aspao_RefCount ++;
  865. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  866. return pRefAddr;
  867. }
  868. VOID FASTCALL
  869. AtalkAspDereferenceAddr(
  870. IN PASP_ADDROBJ pAspAddr
  871. )
  872. /*++
  873. Routine Description:
  874. Arguments:
  875. Return Value:
  876. --*/
  877. {
  878. KIRQL OldIrql;
  879. BOOLEAN Cleanup;
  880. ASSERT(VALID_ASPAO(pAspAddr));
  881. ASSERT (pAspAddr->aspao_RefCount > 0);
  882. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  883. ("AtalkAspDereferenceAddr: Addr %lx, PreCount %ld\n",
  884. pAspAddr, pAspAddr->aspao_RefCount));
  885. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  886. pAspAddr->aspao_RefCount --;
  887. Cleanup = FALSE;
  888. if (pAspAddr->aspao_RefCount == 0)
  889. {
  890. ASSERT (pAspAddr->aspao_Flags & ASPAO_CLOSING);
  891. Cleanup = TRUE;
  892. }
  893. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  894. // Check if this address object is history. Do all the processing needed to make this go
  895. // away. When all is done, clear the event to signal close is complete
  896. if (Cleanup)
  897. {
  898. // At this point we are sure that no active sessions exist on this
  899. // address.
  900. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  901. ("AtalkAspDereferenceAddr: Cleaning up addr %lx\n", pAspAddr));
  902. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  903. ("AtalkAspDereferenceAddr: Indicating close for %lx\n", pAspAddr));
  904. ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
  905. // Call the completion routine to indicate close is successfull
  906. if (pAspAddr->aspao_CloseCompletion != NULL)
  907. (*pAspAddr->aspao_CloseCompletion)(ATALK_NO_ERROR,
  908. pAspAddr->aspao_CloseContext);
  909. // Finally free the memory
  910. AtalkFreeMemory(pAspAddr);
  911. AtalkUnlockAspIfNecessary();
  912. }
  913. }
  914. LOCAL PASP_CONNOBJ
  915. atalkAspReferenceConnBySrcAddr(
  916. IN PASP_ADDROBJ pAspAddr,
  917. IN PATALK_ADDR pSrcAddr,
  918. IN BYTE SessionId
  919. )
  920. /*++
  921. Routine Description:
  922. ASP has the concept of 8-bit session ids which uniquely identifies a
  923. session on a listener. This effectively restricts the number of sessions
  924. to 255 (0 is invalid). To eliminate the restriction, the following
  925. strategy is used.
  926. a, Atp is modified to isolate the transaction ids on a per addr basis
  927. i.e. it monotonically increases for each <net,node,socket> combination.
  928. b, We create session ids on a per <net,node> basis.
  929. Given the following observed facts:
  930. 1, That macintoshes use the sockets starting from the top of the range.
  931. 2, Most network addresses have the same high byte - macintoshes tend
  932. to start from the bottom of the range.
  933. 3, We allocate session ids starting from 1 and most (all) clients will
  934. not have more than one session with us.
  935. It does not make any sense to take either the socket, session id or the
  936. high byte of the network number into account. That leaves only the low
  937. byte of the network, and node id - a nice 16-bit number to hash.
  938. Arguments:
  939. Return Value:
  940. --*/
  941. {
  942. PASP_CONNOBJ pAspConn, pRefConn = NULL;
  943. int index;
  944. ASSERT(VALID_ASPAO(pAspAddr));
  945. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  946. ("AtalkAspReferenceConnBySrcAddr: Addr %lx, Source %x.%x SessionId %d\n",
  947. pAspAddr, pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
  948. index = HASH_SRCADDR(pSrcAddr);
  949. ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  950. for (pAspConn = pAspAddr->aspao_pSessions[index];
  951. pAspConn != NULL;
  952. pAspConn = pAspConn->aspco_NextOverflow)
  953. {
  954. if ((pSrcAddr->ata_Network == pAspConn->aspco_WssRemoteAddr.ata_Network) &&
  955. (pSrcAddr->ata_Node == pAspConn->aspco_WssRemoteAddr.ata_Node) &&
  956. (pAspConn->aspco_SessionId == SessionId))
  957. {
  958. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  959. if ((pAspConn->aspco_Flags & (ASPCO_CLOSING |
  960. ASPCO_CLEANING_UP |
  961. ASPCO_LOCAL_CLOSE |
  962. ASPCO_REMOTE_CLOSE)) == 0)
  963. {
  964. ASSERT(pAspConn->aspco_RefCount > 0);
  965. pAspConn->aspco_RefCount ++;
  966. pRefConn = pAspConn;
  967. }
  968. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  969. break;
  970. }
  971. }
  972. RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  973. return pRefConn;
  974. }
  975. VOID FASTCALL
  976. AtalkAspDereferenceConn(
  977. IN PASP_CONNOBJ pAspConn
  978. )
  979. /*++
  980. Routine Description:
  981. Arguments:
  982. Return Value:
  983. --*/
  984. {
  985. PASP_ADDROBJ pAspAddr = pAspConn->aspco_pAspAddr;
  986. KIRQL OldIrql;
  987. PASP_REQUEST pAspReq;
  988. BOOLEAN Cleanup = FALSE;
  989. ASSERT(VALID_ASPCO(pAspConn));
  990. ASSERT (pAspConn->aspco_RefCount > 0);
  991. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  992. ("AtalkAspDereferenceConn: Conn %lx, PreCount %ld\n",
  993. pAspConn, pAspConn->aspco_RefCount));
  994. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  995. pAspConn->aspco_RefCount --;
  996. if (pAspConn->aspco_RefCount == 0)
  997. {
  998. Cleanup = TRUE;
  999. }
  1000. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  1001. if (!Cleanup)
  1002. {
  1003. return;
  1004. }
  1005. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1006. ("AtalkAspDereferenceConn: Last for %lx\n", pAspConn));
  1007. // The connection is all but dead. Perform the last rites. If its an
  1008. // active session that we're about to shut down, send a close notification
  1009. // to the other side. If it is a remote close, we've already responded to it.
  1010. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1011. ("AtalkAspDereferenceConn: Cleaning up Conn %lx\n", pAspConn));
  1012. ASSERT(VALID_ASPAO(pAspAddr));
  1013. // The connection is in one of the following states:
  1014. // a, Closed remotely - idle
  1015. // b, Active
  1016. //
  1017. // In either case it is in the hash bucket so unlink it
  1018. {
  1019. PASP_CONNOBJ * ppAspConn;
  1020. int index;
  1021. // The connection was active. This is linked into two different
  1022. // lists. Unlink from the hash table here and from the global
  1023. // list later.
  1024. ASSERT(pAspConn->aspco_pActiveReqs == NULL);
  1025. index = HASH_SRCADDR(&pAspConn->aspco_WssRemoteAddr);
  1026. ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
  1027. for (ppAspConn = &pAspAddr->aspao_pSessions[index];
  1028. *ppAspConn != NULL;
  1029. ppAspConn = &(*ppAspConn)->aspco_NextOverflow)
  1030. {
  1031. if (pAspConn == *ppAspConn)
  1032. {
  1033. *ppAspConn = pAspConn->aspco_NextOverflow;
  1034. break;
  1035. }
  1036. }
  1037. RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
  1038. ASSERT (*ppAspConn == pAspConn->aspco_NextOverflow);
  1039. }
  1040. ACQUIRE_SPIN_LOCK(&atalkAspLock, &OldIrql);
  1041. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1042. AtalkUnlinkDouble(pAspConn,
  1043. aspco_NextSession,
  1044. aspco_PrevSession)
  1045. // Free any requests on the free list
  1046. while ((pAspReq = pAspConn->aspco_pFreeReqs) != NULL)
  1047. {
  1048. pAspConn->aspco_pFreeReqs = pAspReq->asprq_Next;
  1049. AtalkBPFreeBlock(pAspReq);
  1050. }
  1051. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1052. RELEASE_SPIN_LOCK(&atalkAspLock, OldIrql);
  1053. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1054. ("AtalkAspDereferenceConn: Indicating close for Conn %lx\n", pAspConn));
  1055. // Call the completion routine to indicate close is successful.
  1056. (*pAspAddr->aspao_ClientEntries.clt_CloseCompletion)(STATUS_SUCCESS,
  1057. pAspConn->aspco_ConnContext);
  1058. // Now Dereference the address object, before we are history
  1059. AtalkAspDereferenceAddr(pAspAddr);
  1060. // Finally free the memory.
  1061. AtalkFreeMemory(pAspConn);
  1062. }
  1063. LOCAL VOID
  1064. atalkAspSlsXHandler(
  1065. IN ATALK_ERROR ErrorCode,
  1066. IN PASP_ADDROBJ pAspAddr, // Listener (our context)
  1067. IN PATP_RESP pAtpResp, // Atp Response context
  1068. IN PATALK_ADDR pSrcAddr, // Address of requestor
  1069. IN USHORT PktLen,
  1070. IN PBYTE pPkt,
  1071. IN PBYTE pUserBytes
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. Handler for incoming requests on the Sls. It handles session opens, tickles
  1076. and get status on the session.
  1077. Arguments:
  1078. Return Value:
  1079. --*/
  1080. {
  1081. PASP_CONNOBJ pAspConn;
  1082. ATALK_ERROR Status;
  1083. PASP_POSTSTAT_CTX pStsCtx;
  1084. int index;
  1085. USHORT StsBufSize;
  1086. BYTE AspCmd, SessionId, StartId;
  1087. BOOLEAN fAddrRefed=FALSE;
  1088. if (!ATALK_SUCCESS(ErrorCode))
  1089. {
  1090. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1091. ("atalkAspSlsXHandler: Error %ld\n", ErrorCode));
  1092. // Take away the reference on the Sls now that the atp address is closing
  1093. if (ErrorCode == ATALK_ATP_CLOSING)
  1094. AtalkAspDereferenceAddr(pAspAddr);
  1095. return;
  1096. }
  1097. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1098. ("atalkAspSlsXHandler: Entered for Function %x from %x.%x\n",
  1099. pUserBytes[ASP_CMD_OFF], pSrcAddr->ata_Network, pSrcAddr->ata_Node));
  1100. switch (AspCmd = pUserBytes[ASP_CMD_OFF])
  1101. {
  1102. case ASP_OPEN_SESSION:
  1103. // Is the version number ok ?
  1104. if ((pUserBytes[ASP_VERSION_OFF] != ASP_VERSION[0]) ||
  1105. (pUserBytes[ASP_VERSION_OFF+1] != ASP_VERSION[1]))
  1106. {
  1107. atalkAspReturnResp( pAtpResp,
  1108. pSrcAddr,
  1109. 0, // SSS
  1110. 0, // SessionId
  1111. ASP_BAD_VERSION); // ErrorCode
  1112. break;
  1113. }
  1114. // Create a connection object corres. to this listen and then notify
  1115. // the client that it needs to handle a new session
  1116. // Allocate memory for a connection object
  1117. if ((pAspConn = AtalkAllocZeroedMemory(sizeof(ASP_CONNOBJ))) != NULL)
  1118. {
  1119. #if DBG
  1120. pAspConn->aspco_Signature = ASPCO_SIGNATURE;
  1121. #endif
  1122. INITIALIZE_SPIN_LOCK(&pAspConn->aspco_Lock);
  1123. pAspConn->aspco_RefCount = 1; // Creation reference
  1124. pAspConn->aspco_pAspAddr = pAspAddr; // Owning address object
  1125. AtalkInitializeRT(&pAspConn->aspco_RT,
  1126. ATP_INITIAL_INTERVAL_FOR_ASP,
  1127. ATP_MIN_INTERVAL_FOR_ASP,
  1128. ATP_MAX_INTERVAL_FOR_ASP);
  1129. }
  1130. ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  1131. if (pAspConn != NULL)
  1132. {
  1133. PASP_CONNOBJ pTmp;
  1134. // Find a session id that we can use for this session. We use
  1135. // the next assignable id, if that is not in use. Otherwise we
  1136. // use the next id not in use by that session. In most cases
  1137. // we have only one session from any client.
  1138. index = HASH_SRCADDR(pSrcAddr);
  1139. // If we do not find any, we use this
  1140. SessionId = StartId = pAspAddr->aspao_NextSessionId++;
  1141. ASSERT (SessionId != 0);
  1142. if (pAspAddr->aspao_NextSessionId == 0)
  1143. pAspAddr->aspao_NextSessionId = 1;
  1144. for (pTmp = pAspAddr->aspao_pSessions[index];
  1145. pTmp != NULL;
  1146. NOTHING)
  1147. {
  1148. if ((pTmp->aspco_WssRemoteAddr.ata_Node == pSrcAddr->ata_Node) &&
  1149. (pTmp->aspco_WssRemoteAddr.ata_Network == pSrcAddr->ata_Network))
  1150. {
  1151. if (pTmp->aspco_SessionId == SessionId)
  1152. {
  1153. // if we have cycled through all, get out!
  1154. if (SessionId == (StartId - 1))
  1155. {
  1156. break;
  1157. }
  1158. SessionId ++;
  1159. if (SessionId == 0)
  1160. {
  1161. // all sessions are taken: quit here!
  1162. if (StartId == 1)
  1163. {
  1164. break;
  1165. }
  1166. SessionId = 1;
  1167. }
  1168. pTmp = pAspAddr->aspao_pSessions[index];
  1169. continue;
  1170. }
  1171. }
  1172. pTmp = pTmp->aspco_NextOverflow;
  1173. }
  1174. // if there are 255 sessions already from this address, then
  1175. // we can't have any more, sorry !!!
  1176. if (SessionId != (StartId - 1))
  1177. {
  1178. // Link it into the hash table
  1179. pAspAddr->aspao_RefCount ++;
  1180. fAddrRefed = TRUE;
  1181. pAspConn->aspco_SessionId = SessionId;
  1182. pAspConn->aspco_cReqsInProcess = 0;
  1183. pAspConn->aspco_WssRemoteAddr.ata_Address = pSrcAddr->ata_Address;
  1184. pAspConn->aspco_WssRemoteAddr.ata_Socket = pUserBytes[ASP_WSS_OFF];
  1185. pAspConn->aspco_LastContactTime = AtalkGetCurrentTick();
  1186. pAspConn->aspco_NextExpectedSeqNum = 0;
  1187. pAspConn->aspco_Flags |= (ASPCO_ACTIVE | ASPCO_TICKLING);
  1188. // The session should be linked *after* all of the above
  1189. // are initialized
  1190. pAspConn->aspco_NextOverflow = pAspAddr->aspao_pSessions[index];
  1191. pAspAddr->aspao_pSessions[index] = pAspConn;
  1192. #ifdef PROFILING
  1193. INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_CurAspSessions,
  1194. &AtalkStatsLock.SpinLock);
  1195. INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_TotalAspSessions,
  1196. &AtalkStatsLock.SpinLock);
  1197. #endif
  1198. }
  1199. else
  1200. {
  1201. AtalkFreeMemory(pAspConn);
  1202. pAspConn = NULL;
  1203. }
  1204. }
  1205. RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  1206. if (pAspConn != NULL)
  1207. {
  1208. BYTE Socket;
  1209. BYTE UserBytes[ATP_USERBYTES_SIZE];
  1210. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1211. ("atalkAspSlsXHandler: Opening session from %d.%d for Session %d\n",
  1212. pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
  1213. // Call the open completion routine and get a context. This is needed
  1214. // before we do anything else. Once we send out an open success it'll
  1215. // be too late.
  1216. // FALSE says this is not over TCP/IP
  1217. pAspConn->aspco_ConnContext =
  1218. (*pAspAddr->aspao_ClientEntries.clt_SessionNotify)(pAspConn,FALSE);
  1219. if (pAspConn->aspco_ConnContext != NULL)
  1220. {
  1221. // Now link the session into the global list
  1222. ACQUIRE_SPIN_LOCK_DPC(&atalkAspLock);
  1223. AtalkLinkDoubleAtHead(atalkAspConnMaint[SessionId & (NUM_ASP_CONN_LISTS-1)].ascm_ConnList,
  1224. pAspConn,
  1225. aspco_NextSession,
  1226. aspco_PrevSession)
  1227. RELEASE_SPIN_LOCK_DPC(&atalkAspLock);
  1228. // Send an open session response - XO
  1229. Socket = pAspAddr->aspao_pSssAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Socket;
  1230. atalkAspReturnResp( pAtpResp,
  1231. pSrcAddr,
  1232. Socket,
  1233. pAspConn->aspco_SessionId,
  1234. 0); // Success
  1235. // Send a tickle out every ASP_TICKLE_INTERVAL seconds
  1236. UserBytes[ASP_CMD_OFF] = ASP_TICKLE;
  1237. UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
  1238. PUTSHORT2SHORT(UserBytes + ASP_ERRORCODE_OFF, 0);
  1239. Status = AtalkAtpPostReq(pAspAddr->aspao_pSlsAtpAddr,
  1240. &pAspConn->aspco_WssRemoteAddr,
  1241. &pAspConn->aspco_TickleXactId,
  1242. ATP_REQ_REMOTE, // Tickle packets are ALO
  1243. NULL,
  1244. 0,
  1245. UserBytes,
  1246. NULL,
  1247. 0,
  1248. ATP_INFINITE_RETRIES,
  1249. ASP_TICKLE_INTERVAL,
  1250. THIRTY_SEC_TIMER,
  1251. NULL,
  1252. NULL);
  1253. if (!ATALK_SUCCESS(Status))
  1254. {
  1255. pAspConn->aspco_Flags &= ~ASPCO_TICKLING;
  1256. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1257. ("atalkAspSlsXHandler: AtalkAtpPostReq %ld\n", Status));
  1258. }
  1259. }
  1260. else
  1261. {
  1262. PASP_CONNOBJ * ppAspConn;
  1263. // Unlink it from the hash table
  1264. ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  1265. for (ppAspConn = &pAspAddr->aspao_pSessions[index];
  1266. *ppAspConn != NULL;
  1267. ppAspConn = &(*ppAspConn)->aspco_NextOverflow)
  1268. {
  1269. if (*ppAspConn == pAspConn)
  1270. {
  1271. *ppAspConn = pAspConn->aspco_NextOverflow;
  1272. break;
  1273. }
  1274. }
  1275. ASSERT (*ppAspConn == pAspConn->aspco_NextOverflow);
  1276. RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  1277. AtalkFreeMemory(pAspConn);
  1278. pAspConn = NULL;
  1279. #ifdef PROFILING
  1280. INTERLOCKED_DECREMENT_LONG_DPC(&AtalkStatistics.stat_CurAspSessions,
  1281. &AtalkStatsLock.SpinLock);
  1282. INTERLOCKED_DECREMENT_LONG_DPC(&AtalkStatistics.stat_TotalAspSessions,
  1283. &AtalkStatsLock.SpinLock);
  1284. #endif
  1285. }
  1286. }
  1287. // If we are set to disable listens or could not allocate memory, drop it
  1288. if (pAspConn == NULL)
  1289. {
  1290. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1291. ("atalkAspSlsXHandler: No conn objects available\n"));
  1292. atalkAspReturnResp( pAtpResp,
  1293. pSrcAddr,
  1294. 0,
  1295. 0,
  1296. ASP_SERVER_BUSY);
  1297. // remove that refcount if we put it in hoping afp would accept the request
  1298. if (fAddrRefed)
  1299. {
  1300. AtalkAspDereferenceAddr(pAspAddr);
  1301. }
  1302. }
  1303. break;
  1304. case ASP_GET_STATUS:
  1305. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1306. ("atalkAspSssXHandler: Received GetStat from %x.%x\n",
  1307. pSrcAddr->ata_Network, pSrcAddr->ata_Node));
  1308. // Create an Mdl to describe the status buffer and post a response
  1309. // to the GetStatus request
  1310. StsBufSize = 0;
  1311. pStsCtx = NULL;
  1312. ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  1313. if (pAspAddr->aspao_pStatusBuf != NULL)
  1314. {
  1315. pStsCtx = (PASP_POSTSTAT_CTX)AtalkAllocMemory(sizeof(ASP_POSTSTAT_CTX) +
  1316. pAspAddr->aspao_StsBufSize);
  1317. if (pStsCtx != NULL)
  1318. {
  1319. pStsCtx->aps_pAMdl = AtalkAllocAMdl((PBYTE)pStsCtx + sizeof(ASP_POSTSTAT_CTX),
  1320. pAspAddr->aspao_StsBufSize);
  1321. if (pStsCtx->aps_pAMdl != NULL)
  1322. {
  1323. pStsCtx->aps_pAtpResp = pAtpResp;
  1324. StsBufSize = pAspAddr->aspao_StsBufSize;
  1325. RtlCopyMemory((PBYTE)pStsCtx + sizeof(ASP_POSTSTAT_CTX),
  1326. pAspAddr->aspao_pStatusBuf,
  1327. StsBufSize);
  1328. }
  1329. else
  1330. {
  1331. AtalkFreeMemory(pStsCtx);
  1332. pStsCtx = NULL;
  1333. StsBufSize = 0;
  1334. }
  1335. }
  1336. }
  1337. RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
  1338. Status = AtalkAtpPostResp(pAtpResp,
  1339. pSrcAddr,
  1340. (pStsCtx != NULL) ?
  1341. pStsCtx->aps_pAMdl : NULL,
  1342. StsBufSize,
  1343. NULL,
  1344. atalkAspRespComplete,
  1345. pStsCtx);
  1346. if (!ATALK_SUCCESS(Status))
  1347. {
  1348. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1349. ("atalkAspSlsXHandler: AtalkAtpPostResp %ld\n", Status));
  1350. atalkAspRespComplete(Status, pStsCtx);
  1351. }
  1352. break;
  1353. case ASP_TICKLE:
  1354. SessionId = pUserBytes[ASP_SESSIONID_OFF];
  1355. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1356. ("atalkAspSssXHandler: Received tickle from %x.%x Session %d\n",
  1357. pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
  1358. if ((pAspConn = atalkAspReferenceConnBySrcAddr(pAspAddr, pSrcAddr, SessionId)) != NULL)
  1359. {
  1360. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1361. pAspConn->aspco_LastContactTime = AtalkGetCurrentTick();
  1362. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1363. AtalkAspDereferenceConn(pAspConn);
  1364. }
  1365. else
  1366. {
  1367. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1368. ("atalkAspSssXHandler: Conn not found for addr %d.%d Session %d\n",
  1369. pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
  1370. }
  1371. // Fall through to the default case
  1372. default:
  1373. // Cancel this response since we never respond to it and we want this to go away
  1374. AtalkAtpCancelResp(pAtpResp);
  1375. if (AspCmd != ASP_TICKLE)
  1376. {
  1377. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1378. ("atalkAspSlsXHandler: Invalid command\n"));
  1379. }
  1380. break;
  1381. }
  1382. }
  1383. LOCAL VOID
  1384. atalkAspSssXHandler(
  1385. IN ATALK_ERROR ErrorCode,
  1386. IN PASP_ADDROBJ pAspAddr, // Listener (our context)
  1387. IN PATP_RESP pAtpResp, // Atp Response context
  1388. IN PATALK_ADDR pSrcAddr, // Address of requestor
  1389. IN USHORT PktLen,
  1390. IN PBYTE pPkt,
  1391. IN PBYTE pUserBytes
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. Handler for incoming requests on the Sss. It handles incoming requests, close
  1396. and write continue.
  1397. Arguments:
  1398. Return Value:
  1399. --*/
  1400. {
  1401. PASP_CONNOBJ pAspConn; // Session which will handle this request
  1402. PASP_REQUEST pAspReq; // The request that will be satisfied
  1403. ATALK_ERROR Status;
  1404. NTSTATUS retStatus;
  1405. USHORT SequenceNum; // From the incoming packet
  1406. BYTE SessionId; // -- ditto --
  1407. BYTE RequestType; // -- ditto --
  1408. BOOLEAN CancelResp = FALSE,
  1409. CancelTickle;
  1410. BOOLEAN fTellAfp=TRUE;
  1411. do
  1412. {
  1413. if (!ATALK_SUCCESS(ErrorCode))
  1414. {
  1415. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1416. ("atalkAspSssXHandler: Error %ld\n", ErrorCode));
  1417. // Take away the reference on the Sls now that the atp address is closing
  1418. if (ErrorCode == ATALK_ATP_CLOSING)
  1419. AtalkAspDereferenceAddr(pAspAddr);
  1420. break;
  1421. }
  1422. // Get the session id out of the packet and reference the session that this
  1423. // request is targeted to.
  1424. SessionId = pUserBytes[ASP_SESSIONID_OFF];
  1425. RequestType = pUserBytes[ASP_CMD_OFF];
  1426. GETSHORT2SHORT(&SequenceNum, pUserBytes+ASP_SEQUENCE_NUM_OFF);
  1427. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1428. ("atalkAspSssXHandler: Entered for Request %x from %x.%x\n",
  1429. RequestType, pSrcAddr->ata_Network, pSrcAddr->ata_Node));
  1430. // The reference for this connection is passed down to the request
  1431. // for the ASP_CMD & ASP_WRITE case.
  1432. pAspConn = atalkAspReferenceConnBySrcAddr(pAspAddr, pSrcAddr, SessionId);
  1433. if (pAspConn == NULL)
  1434. {
  1435. CancelResp = TRUE;
  1436. break;
  1437. }
  1438. ASSERT (pAspConn->aspco_pAspAddr == pAspAddr);
  1439. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1440. pAspConn->aspco_LastContactTime = AtalkGetCurrentTick();
  1441. switch (RequestType)
  1442. {
  1443. case ASP_CMD:
  1444. case ASP_WRITE:
  1445. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1446. ("atalkAspSssXHandler: %s\n",
  1447. (RequestType == ASP_CMD) ? "Command" : "Write"));
  1448. // Create a request for this and notify the client to handle this
  1449. // Validate the incoming sequence number. Reject if out of sequence
  1450. if (SequenceNum == pAspConn->aspco_NextExpectedSeqNum)
  1451. {
  1452. // We now have a request to be handled.
  1453. // The reference to the connection above will be passed on
  1454. // to the request. This will get de-referenced when the
  1455. // request is replied to. See if we have a free request to pick up
  1456. // Allocate a request structure if not and link it in the listener object
  1457. if ((pAspReq = pAspConn->aspco_pFreeReqs) != NULL)
  1458. pAspConn->aspco_pFreeReqs = pAspReq->asprq_Next;
  1459. else pAspReq = AtalkBPAllocBlock(BLKID_ASPREQ);
  1460. if (pAspReq != NULL)
  1461. {
  1462. pAspConn->aspco_NextExpectedSeqNum ++;
  1463. #if DBG
  1464. pAspReq->asprq_Signature = ASPRQ_SIGNATURE;
  1465. #endif
  1466. pAspReq->asprq_pAtpResp = pAtpResp;
  1467. pAspReq->asprq_pAspConn = pAspConn;
  1468. pAspReq->asprq_ReqType = RequestType;
  1469. pAspReq->asprq_SeqNum = SequenceNum;
  1470. pAspReq->asprq_RemoteAddr = *pSrcAddr;
  1471. pAspReq->asprq_Flags = 0;
  1472. pAspReq->asprq_Request.rq_WriteMdl = NULL;
  1473. pAspReq->asprq_Request.rq_CacheMgrContext = NULL;
  1474. pAspReq->asprq_Request.rq_RequestSize = PktLen;
  1475. pAspReq->asprq_Next = pAspConn->aspco_pActiveReqs;
  1476. pAspConn->aspco_cReqsInProcess ++;
  1477. pAspConn->aspco_pActiveReqs = pAspReq;
  1478. ASSERT ((pAspConn->aspco_Flags & (ASPCO_CLEANING_UP |
  1479. ASPCO_CLOSING |
  1480. ASPCO_LOCAL_CLOSE |
  1481. ASPCO_REMOTE_CLOSE)) == 0);
  1482. }
  1483. }
  1484. else
  1485. {
  1486. pAspReq = NULL;
  1487. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1488. ("atalkAspSssXHandler: Sequence mismatch exp %x, act %x\n",
  1489. pAspConn->aspco_NextExpectedSeqNum, SequenceNum));
  1490. }
  1491. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1492. // If we do not have an request to handle this, cancel the
  1493. // response. Otherwise the client will keep retrying and atp
  1494. // will not tell us since it already has.
  1495. if (pAspReq == NULL)
  1496. {
  1497. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1498. ("atalkAspSssXHandler: Dropping request for session %d from %d.%d\n",
  1499. SessionId, pSrcAddr->ata_Network, pSrcAddr->ata_Node));
  1500. CancelResp = TRUE;
  1501. AtalkAspDereferenceConn(pAspConn);
  1502. break;
  1503. }
  1504. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1505. ("atalkAspSssXHandler: Indicating Request %lx\n", pAspReq));
  1506. if (RequestType == ASP_WRITE)
  1507. {
  1508. if (PktLen > MAX_WRITE_REQ_SIZE)
  1509. {
  1510. PASP_REQUEST *ppTmpAspReq;
  1511. ASSERT(0);
  1512. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1513. for (ppTmpAspReq = &pAspConn->aspco_pActiveReqs;
  1514. *ppTmpAspReq != NULL; ppTmpAspReq = &(*ppTmpAspReq)->asprq_Next )
  1515. {
  1516. if (pAspReq == *ppTmpAspReq)
  1517. {
  1518. *ppTmpAspReq = pAspReq->asprq_Next;
  1519. break;
  1520. }
  1521. }
  1522. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1523. AtalkAspDereferenceConn(pAspConn);
  1524. AtalkBPFreeBlock(pAspReq);
  1525. pAspReq = NULL;
  1526. CancelResp = TRUE;
  1527. break;
  1528. }
  1529. RtlCopyMemory(pAspReq->asprq_ReqBuf, pPkt, PktLen);
  1530. pAspReq->asprq_Request.rq_RequestBuf = pAspReq->asprq_ReqBuf;
  1531. retStatus = (*pAspAddr->aspao_ClientEntries.clt_GetWriteBuffer)
  1532. (pAspConn->aspco_ConnContext,&pAspReq->asprq_Request);
  1533. //
  1534. // most common case: file server will pend it so it can go to cache mgr
  1535. //
  1536. if (retStatus == STATUS_PENDING)
  1537. {
  1538. fTellAfp = FALSE;
  1539. break;
  1540. }
  1541. else if (retStatus == STATUS_SUCCESS)
  1542. {
  1543. if (pAspReq->asprq_Request.rq_WriteMdl != NULL)
  1544. {
  1545. atalkAspPostWriteContinue(pAspReq);
  1546. // we informed (or will inform) AFP about this request: don't
  1547. // inform again below!
  1548. fTellAfp = FALSE;
  1549. }
  1550. }
  1551. else
  1552. {
  1553. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1554. ("atalkAspSssXHandler: GetWriteBuffer returned %lx on %lx\n",
  1555. retStatus,pAspConn));
  1556. }
  1557. }
  1558. // TRUE for CMD as well
  1559. if ((pAspReq->asprq_Request.rq_WriteMdl == NULL) &&
  1560. (fTellAfp))
  1561. {
  1562. pAspReq->asprq_Request.rq_RequestBuf = pPkt;
  1563. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  1564. // Notify the client that it has a request to handle
  1565. retStatus = (*pAspAddr->aspao_ClientEntries.clt_RequestNotify)
  1566. (STATUS_SUCCESS,
  1567. pAspConn->aspco_ConnContext,
  1568. &pAspReq->asprq_Request);
  1569. if (!NT_SUCCESS(retStatus))
  1570. {
  1571. PASP_REQUEST *ppTmpAspReq;
  1572. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1573. ("atalkAspSssXHandler: Afp didn't accept request %lx on conn %lx\n",
  1574. pAspReq,pAspConn));
  1575. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1576. for (ppTmpAspReq = &pAspConn->aspco_pActiveReqs;
  1577. *ppTmpAspReq != NULL; ppTmpAspReq = &(*ppTmpAspReq)->asprq_Next )
  1578. {
  1579. if (pAspReq == *ppTmpAspReq)
  1580. {
  1581. *ppTmpAspReq = pAspReq->asprq_Next;
  1582. break;
  1583. }
  1584. }
  1585. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1586. AtalkAspDereferenceConn(pAspConn);
  1587. AtalkBPFreeBlock(pAspReq);
  1588. pAspReq = NULL;
  1589. CancelResp = TRUE;
  1590. }
  1591. }
  1592. break;
  1593. case ASP_CLOSE_SESSION:
  1594. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1595. ("atalkAspSssXHandler: Close request from %d.%d for Session %d\n",
  1596. pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
  1597. #ifdef PROFILING
  1598. INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_AspSessionsClosed,
  1599. &AtalkStatsLock.SpinLock);
  1600. #endif
  1601. CancelTickle = ((pAspConn->aspco_Flags &ASPCO_TICKLING) != 0);
  1602. pAspConn->aspco_Flags &= ~(ASPCO_ACTIVE | ASPCO_TICKLING);
  1603. pAspConn->aspco_Flags |= ASPCO_REMOTE_CLOSE;
  1604. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1605. // Send a CloseSession reply and close the session
  1606. Status = AtalkAtpPostResp(pAtpResp,
  1607. pSrcAddr,
  1608. NULL,
  1609. 0,
  1610. NULL,
  1611. AtalkAtpGenericRespComplete,
  1612. pAtpResp);
  1613. if (!ATALK_SUCCESS(Status))
  1614. {
  1615. AtalkAtpGenericRespComplete(Status, pAtpResp);
  1616. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1617. ("atalkAspSssXHandler: AtalkAtpPostResp failed %ld\n", Status));
  1618. }
  1619. // Cancel the tickle requests for this session
  1620. if (CancelTickle)
  1621. {
  1622. Status = AtalkAtpCancelReq(pAspAddr->aspao_pSlsAtpAddr,
  1623. pAspConn->aspco_TickleXactId,
  1624. &pAspConn->aspco_WssRemoteAddr);
  1625. if (!ATALK_SUCCESS(Status))
  1626. {
  1627. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1628. ("atalkAspSssXHandler: AtalkAtpCancelReq %ld\n", Status));
  1629. }
  1630. }
  1631. // Shut down this session, well almost ... Note that we have a reference
  1632. // to this connection which will be Dereferenced by atalkAspSessionClose.
  1633. atalkAspSessionClose(pAspConn);
  1634. break;
  1635. default:
  1636. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1637. CancelResp = TRUE;
  1638. AtalkAspDereferenceConn(pAspConn);
  1639. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1640. ("atalkAspSssXHandler: Invalid command %d\n", RequestType));
  1641. break;
  1642. }
  1643. } while (FALSE);
  1644. if (CancelResp)
  1645. {
  1646. Status = AtalkAtpCancelResp(pAtpResp);
  1647. if (!ATALK_SUCCESS(Status))
  1648. {
  1649. DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_ERR,
  1650. ("atalkAspSssXHandler: AtalkAspCancelResp %ld\n", Status));
  1651. }
  1652. }
  1653. }
  1654. LOCAL VOID FASTCALL
  1655. atalkAspReplyRelease(
  1656. IN ATALK_ERROR ErrorCode,
  1657. IN PASP_REQUEST pAspReq
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. Handler for incoming release for reply
  1662. Arguments:
  1663. Return Value:
  1664. --*/
  1665. {
  1666. PASP_CONNOBJ pAspConn;
  1667. PASP_ADDROBJ pAspAddr;
  1668. KIRQL OldIrql;
  1669. NTSTATUS Status = STATUS_SUCCESS;
  1670. ASSERT (VALID_ASPRQ(pAspReq));
  1671. pAspConn = pAspReq->asprq_pAspConn;
  1672. ASSERT (VALID_ASPCO(pAspConn));
  1673. pAspAddr = pAspConn->aspco_pAspAddr;
  1674. ASSERT (VALID_ASPAO(pAspAddr));
  1675. ASSERT ((pAspReq->asprq_Flags & ASPRQ_REPLY) || !ATALK_SUCCESS(ErrorCode));
  1676. if (!NT_SUCCESS(ErrorCode))
  1677. {
  1678. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  1679. ("atalkAspReplyRelease: Failure %ld\n", ErrorCode));
  1680. Status = AtalkErrorToNtStatus(ErrorCode);
  1681. }
  1682. // We complete here
  1683. (*pAspAddr->aspao_ClientEntries.clt_ReplyCompletion)(Status,
  1684. pAspConn->aspco_ConnContext,
  1685. &pAspReq->asprq_Request);
  1686. // Based on whether a reply was actually sent or not, either deref the response
  1687. // or cancel it.
  1688. if (pAspReq->asprq_Flags & ASPRQ_REPLY)
  1689. {
  1690. AtalkAtpRespDereference(pAspReq->asprq_pAtpResp);
  1691. }
  1692. else
  1693. {
  1694. AtalkAtpCancelResp(pAspReq->asprq_pAtpResp);
  1695. }
  1696. // make sure we aren't hanging on to cache mgr's mdl!
  1697. ASSERT(pAspReq->asprq_Request.rq_CacheMgrContext == NULL);
  1698. #if DBG
  1699. pAspReq->asprq_Signature = 0x28041998;
  1700. pAspReq->asprq_pAtpResp = (PATP_RESP)(pAspReq->asprq_Request.rq_WriteMdl);
  1701. pAspReq->asprq_pAspConn = (PASP_CONNOBJ)(pAspReq->asprq_Request.rq_CacheMgrContext);
  1702. pAspReq->asprq_Request.rq_WriteMdl = (PMDL)0x44556677;
  1703. pAspReq->asprq_Request.rq_CacheMgrContext = (PVOID)66778899;
  1704. #endif
  1705. // Free this as we are done with this request now
  1706. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  1707. if (pAspConn->aspco_pFreeReqs == NULL)
  1708. {
  1709. pAspReq->asprq_Next = NULL;
  1710. pAspConn->aspco_pFreeReqs = pAspReq;
  1711. }
  1712. else AtalkBPFreeBlock(pAspReq);
  1713. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  1714. // We are done with this request.
  1715. AtalkAspDereferenceConn(pAspConn);
  1716. }
  1717. LOCAL VOID
  1718. atalkAspWriteContinueResp(
  1719. IN ATALK_ERROR ErrorCode,
  1720. IN PASP_REQUEST pAspReq,
  1721. IN PAMDL pReqAMdl,
  1722. IN PAMDL pRespAMdl,
  1723. IN USHORT RespSize,
  1724. IN PBYTE RespUserBytes
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. Handler for incoming write continue response.
  1729. Arguments:
  1730. Return Value:
  1731. --*/
  1732. {
  1733. PASP_CONNOBJ pAspConn;
  1734. PASP_ADDROBJ pAspAddr;
  1735. NTSTATUS Status;
  1736. NTSTATUS retStatus;
  1737. KIRQL OldIrql;
  1738. PASP_REQUEST * ppAspReq;
  1739. PVOID pClientContxt;
  1740. ASSERT (VALID_ASPRQ(pAspReq));
  1741. ASSERT(pAspReq->asprq_Flags & ASPRQ_WRTCONT);
  1742. pAspConn = pAspReq->asprq_pAspConn;
  1743. ASSERT(VALID_ASPCO(pAspConn));
  1744. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1745. ("atalkAspWriteContinueResp: Entered for request %lx\n", pAspReq));
  1746. pAspAddr = pAspConn->aspco_pAspAddr;
  1747. ASSERT(VALID_ASPAO(pAspAddr));
  1748. pAspReq->asprq_Flags &= ~ASPRQ_WRTCONT;
  1749. pClientContxt = pAspConn->aspco_ConnContext;
  1750. if (ATALK_SUCCESS(ErrorCode))
  1751. {
  1752. pAspConn->aspco_RT.rt_New = AtalkGetCurrentTick() - pAspConn->aspco_RT.rt_New;
  1753. // Estimate the retry interval for next time.
  1754. AtalkCalculateNewRT(&pAspConn->aspco_RT);
  1755. Status = STATUS_SUCCESS;
  1756. }
  1757. else
  1758. {
  1759. Status = AtalkErrorToNtStatus(ErrorCode);
  1760. }
  1761. #ifdef PROFILING
  1762. {
  1763. KIRQL OldIrql;
  1764. ACQUIRE_SPIN_LOCK(&AtalkStatsLock, &OldIrql);
  1765. AtalkStatistics.stat_LastAspRTT = (ULONG)(pAspConn->aspco_RT.rt_Base);
  1766. if ((ULONG)(pAspConn->aspco_RT.rt_Base) > AtalkStatistics.stat_MaxAspRTT)
  1767. AtalkStatistics.stat_MaxAspRTT = (ULONG)(pAspConn->aspco_RT.rt_Base);
  1768. RELEASE_SPIN_LOCK(&AtalkStatsLock, OldIrql);
  1769. }
  1770. #endif
  1771. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1772. ("atalkAspWriteContinueResp: Indicating request %lx\n", pAspReq));
  1773. // Notify the client that it has a request to handle
  1774. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  1775. retStatus = (*pAspAddr->aspao_ClientEntries.clt_RequestNotify)
  1776. (Status,
  1777. pClientContxt,
  1778. &pAspReq->asprq_Request);
  1779. KeLowerIrql(OldIrql);
  1780. //
  1781. // In case the writecontinue returned an error, this request needs to go away
  1782. // since there will never be a call to AtalkAspReply(). Also deref the conn.
  1783. // Alternately, if the response came in fine, but the server didn't want to accept
  1784. // it, it's the same deal
  1785. //
  1786. if ( (!NT_SUCCESS(Status)) || (!NT_SUCCESS(retStatus)) )
  1787. {
  1788. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1789. ("atalkAspWriteContinueResp: incoming %lx, Afp %lx req: %lx on %lx, cancelling\n",
  1790. Status,retStatus,pAspReq,pAspConn));
  1791. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  1792. for (ppAspReq = &pAspConn->aspco_pActiveReqs;
  1793. *ppAspReq != NULL;
  1794. ppAspReq = &(*ppAspReq)->asprq_Next)
  1795. {
  1796. if (pAspReq == *ppAspReq)
  1797. {
  1798. *ppAspReq = pAspReq->asprq_Next;
  1799. pAspConn->aspco_cReqsInProcess --;
  1800. break;
  1801. }
  1802. }
  1803. ASSERT (*ppAspReq == pAspReq->asprq_Next);
  1804. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  1805. AtalkAspDereferenceConn(pAspConn);
  1806. // Cancel the response for the original request that caused wrtcont to be posted
  1807. AtalkAtpCancelResp(pAspReq->asprq_pAtpResp);
  1808. // Free this request as well
  1809. AtalkBPFreeBlock(pAspReq);
  1810. }
  1811. if (pReqAMdl)
  1812. {
  1813. ASSERT (AtalkGetAddressFromMdlSafe(pReqAMdl, NormalPagePriority) == pAspReq->asprq_WrtContRespBuf);
  1814. ASSERT (AtalkSizeMdlChain(pReqAMdl) == ASP_WRITE_DATA_SIZE);
  1815. AtalkFreeAMdl(pReqAMdl);
  1816. }
  1817. }
  1818. LOCAL VOID
  1819. atalkAspSendAttentionResp(
  1820. IN ATALK_ERROR ErrorCode,
  1821. IN PVOID pContext,
  1822. IN PAMDL pReqAMdl,
  1823. IN PAMDL pRespAMdl,
  1824. IN USHORT RespSize,
  1825. IN PBYTE RespUserBytes
  1826. )
  1827. /*++
  1828. Routine Description:
  1829. Handler for incoming write continue response.
  1830. Arguments:
  1831. Return Value:
  1832. --*/
  1833. {
  1834. PBYTE pBuf;
  1835. PASP_CONNOBJ pAspConn = (PASP_CONNOBJ)pContext;
  1836. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1837. ("atalkAspSendAttentionResp: Entered for conn %lx\n", pAspConn));
  1838. if (!ATALK_SUCCESS(ErrorCode))
  1839. {
  1840. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1841. ("atalkAspSendAttentionResp: Failure %ld\n", ErrorCode));
  1842. }
  1843. if (pRespAMdl != NULL)
  1844. {
  1845. pBuf = AtalkGetAddressFromMdlSafe(
  1846. pRespAMdl,
  1847. NormalPagePriority);
  1848. if (pBuf != NULL)
  1849. {
  1850. AtalkFreeMemory(pBuf);
  1851. }
  1852. AtalkFreeAMdl(pRespAMdl);
  1853. }
  1854. // Call the completion routine
  1855. (*pAspConn->aspco_pAspAddr->aspao_ClientEntries.clt_AttnCompletion)(pAspConn->aspco_AttentionContext);
  1856. pAspConn->aspco_AttentionContext = NULL;
  1857. // Finally Dereference the connection
  1858. AtalkAspDereferenceConn(pAspConn);
  1859. }
  1860. LOCAL LONG FASTCALL
  1861. atalkAspSessionMaintenanceTimer(
  1862. IN PTIMERLIST pTimer,
  1863. IN BOOLEAN TimerShuttingDown
  1864. )
  1865. /*++
  1866. Routine Description:
  1867. Arguments:
  1868. Return Value:
  1869. --*/
  1870. {
  1871. PASP_CONNOBJ pAspConn, pAspConnNext;
  1872. PASP_CONN_MAINT pAspCM;
  1873. BOOLEAN Close = FALSE;
  1874. LONG CurrentTick = AtalkGetCurrentTick();
  1875. #ifdef PROFILING
  1876. TIME TimeS, TimeE, TimeD;
  1877. TimeS = KeQueryPerformanceCounter(NULL);
  1878. #endif
  1879. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1880. ("atalkAspSessionMaintenanceTimer: Entered\n"));
  1881. if (TimerShuttingDown)
  1882. return ATALK_TIMER_NO_REQUEUE;
  1883. pAspCM = CONTAINING_RECORD(pTimer, ASP_CONN_MAINT, ascm_SMTTimer);
  1884. ACQUIRE_SPIN_LOCK_DPC(&atalkAspLock);
  1885. // Walk the list of sessions on the global list and shut down
  1886. // sessions that have not tickle'd for a while
  1887. for (pAspConn = pAspCM->ascm_ConnList; pAspConn != NULL; pAspConn = pAspConnNext)
  1888. {
  1889. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  1890. ("atalkAspSessionMaintenanceTimer: Checking out session %d from %x.%x\n",
  1891. pAspConn->aspco_SessionId,
  1892. pAspConn->aspco_WssRemoteAddr.ata_Network,
  1893. pAspConn->aspco_WssRemoteAddr.ata_Node));
  1894. pAspConnNext = pAspConn->aspco_NextSession;
  1895. Close = FALSE;
  1896. ASSERT (VALID_ASPCO(pAspConn));
  1897. ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1898. if ((pAspConn->aspco_Flags & ASPCO_ACTIVE) &&
  1899. ((CurrentTick - pAspConn->aspco_LastContactTime) > ASP_MAX_SESSION_IDLE_TIME))
  1900. {
  1901. pAspConn->aspco_Flags |= (ASPCO_REMOTE_CLOSE | ASPCO_DROPPED);
  1902. pAspConn->aspco_Flags &= ~ASPCO_ACTIVE;
  1903. pAspConn->aspco_RefCount ++; // Since atalkAspSessionClose Derefs it
  1904. Close = TRUE;
  1905. }
  1906. RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
  1907. if (Close)
  1908. {
  1909. PASP_ADDROBJ pAspAddr;
  1910. ATALK_ERROR Status;
  1911. #ifdef PROFILING
  1912. INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_AspSessionsDropped,
  1913. &AtalkStatsLock.SpinLock);
  1914. #endif
  1915. pAspAddr = pAspConn->aspco_pAspAddr;
  1916. ASSERT (VALID_ASPAO(pAspAddr));
  1917. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1918. ("atalkAspSessionMaintenanceTimer: Shutting down session %d from %x.%x\n",
  1919. pAspConn->aspco_SessionId,
  1920. pAspConn->aspco_WssRemoteAddr.ata_Network,
  1921. pAspConn->aspco_WssRemoteAddr.ata_Node));
  1922. RELEASE_SPIN_LOCK_DPC(&atalkAspLock);
  1923. // This session is being punted. Cancel tickles on this and notify the
  1924. // server that this session is history.
  1925. Status = AtalkAtpCancelReq(pAspAddr->aspao_pSlsAtpAddr,
  1926. pAspConn->aspco_TickleXactId,
  1927. &pAspConn->aspco_WssRemoteAddr);
  1928. if (!ATALK_SUCCESS(Status))
  1929. {
  1930. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  1931. ("atalkAspSessionMaintenanceTimer: AtalkAtpCancelReq %ld\n", Status));
  1932. }
  1933. // Shut down this session, well almost ...
  1934. atalkAspSessionClose(pAspConn);
  1935. ACQUIRE_SPIN_LOCK_DPC(&atalkAspLock);
  1936. pAspConnNext = pAspCM->ascm_ConnList;
  1937. }
  1938. }
  1939. #ifdef PROFILING
  1940. TimeE = KeQueryPerformanceCounter(NULL);
  1941. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  1942. INTERLOCKED_ADD_LARGE_INTGR_DPC(&AtalkStatistics.stat_AspSmtProcessTime,
  1943. TimeD,
  1944. &AtalkStatsLock.SpinLock);
  1945. INTERLOCKED_INCREMENT_LONG_DPC( &AtalkStatistics.stat_AspSmtCount,
  1946. &AtalkStatsLock.SpinLock);
  1947. #endif
  1948. RELEASE_SPIN_LOCK_DPC(&atalkAspLock);
  1949. // Reschedule ourselves
  1950. return ATALK_TIMER_REQUEUE;
  1951. }
  1952. LOCAL VOID
  1953. atalkAspSessionClose(
  1954. IN PASP_CONNOBJ pAspConn
  1955. )
  1956. /*++
  1957. Routine Description:
  1958. This should be called with a reference to the connection which is Dereferenced
  1959. here.
  1960. Arguments:
  1961. Return Value:
  1962. --*/
  1963. {
  1964. PASP_REQUEST pAspReq, pAspReqNext;
  1965. PASP_ADDROBJ pAspAddr = pAspConn->aspco_pAspAddr;
  1966. REQUEST Request;
  1967. KIRQL OldIrql;
  1968. NTSTATUS Status = STATUS_REMOTE_DISCONNECT;
  1969. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  1970. pAspConn->aspco_Flags &= ~ASPCO_ACTIVE;
  1971. // Cancel any Write-continues pending. Do not bother cancelling
  1972. // replies as they will time out anyway. Also atalkAspReplyRelease()
  1973. // will attempt to acquire the connection lock and we're already
  1974. // holding it
  1975. for (pAspReq = pAspConn->aspco_pActiveReqs;
  1976. pAspReq != NULL;
  1977. pAspReq = pAspReqNext)
  1978. {
  1979. pAspReqNext = pAspReq->asprq_Next;
  1980. if ((pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_WRTCONT_CANCELLED)) == ASPRQ_WRTCONT)
  1981. {
  1982. pAspReq->asprq_Flags |= ASPRQ_WRTCONT_CANCELLED;
  1983. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  1984. AtalkAtpCancelReq(pAspAddr->aspao_pSssAtpAddr,
  1985. pAspReq->asprq_WCXactId,
  1986. &pAspConn->aspco_WssRemoteAddr);
  1987. ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
  1988. pAspReqNext = pAspConn->aspco_pActiveReqs;
  1989. }
  1990. }
  1991. RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
  1992. if (pAspConn->aspco_Flags & ASPCO_DROPPED)
  1993. {
  1994. Status = STATUS_LOCAL_DISCONNECT;
  1995. }
  1996. // Indicate a request with an error to indicate that the session closed remotely.
  1997. // Pass the remote address of the client so that the server can log an event if
  1998. // the session did not shutdown gracefully.
  1999. Request.rq_RequestSize = (LONG)(pAspConn->aspco_WssRemoteAddr.ata_Address);
  2000. Request.rq_RequestBuf = NULL;
  2001. Request.rq_WriteMdl = NULL;
  2002. Request.rq_CacheMgrContext = NULL;
  2003. (*pAspAddr->aspao_ClientEntries.clt_RequestNotify)(Status,
  2004. pAspConn->aspco_ConnContext,
  2005. &Request);
  2006. // Finally Dereference the session
  2007. AtalkAspDereferenceConn(pAspConn);
  2008. }
  2009. LOCAL VOID
  2010. atalkAspReturnResp(
  2011. IN PATP_RESP pAtpResp,
  2012. IN PATALK_ADDR pDstAddr,
  2013. IN BYTE Byte0,
  2014. IN BYTE Byte1,
  2015. IN USHORT Word2
  2016. )
  2017. /*++
  2018. Routine Description:
  2019. Arguments:
  2020. Return Value:
  2021. --*/
  2022. {
  2023. BYTE UserBytes[ATP_USERBYTES_SIZE];
  2024. ATALK_ERROR Status;
  2025. UserBytes[0] = Byte0;
  2026. UserBytes[1] = Byte1;
  2027. PUTSHORT2SHORT(UserBytes+2, Word2);
  2028. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  2029. ("atalkAspReturnResp: For Resp %lx\n", pAtpResp));
  2030. Status = AtalkAtpPostResp(pAtpResp,
  2031. pDstAddr,
  2032. NULL,
  2033. 0,
  2034. UserBytes,
  2035. AtalkAtpGenericRespComplete,
  2036. pAtpResp);
  2037. if (!ATALK_SUCCESS(Status))
  2038. {
  2039. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  2040. ("atalkAspReturnResp: AtalkAtpPostResp failed %ld\n", Status));
  2041. AtalkAtpGenericRespComplete(Status, pAtpResp);
  2042. }
  2043. }
  2044. LOCAL VOID FASTCALL
  2045. atalkAspRespComplete(
  2046. IN ATALK_ERROR ErrorCode,
  2047. IN PASP_POSTSTAT_CTX pStsCtx
  2048. )
  2049. /*++
  2050. Routine Description:
  2051. Arguments:
  2052. Return Value:
  2053. --*/
  2054. {
  2055. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
  2056. ("atalkAspRespComplete: Entered pStsCtx %lx\n", pStsCtx));
  2057. if (!ATALK_SUCCESS(ErrorCode))
  2058. {
  2059. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
  2060. ("atalkAspRespComplete: Failed %ld, pStsCtx %lx\n", ErrorCode, pStsCtx));
  2061. }
  2062. if (pStsCtx != NULL)
  2063. {
  2064. AtalkFreeAMdl(pStsCtx->aps_pAMdl);
  2065. AtalkAtpRespDereferenceDpc(pStsCtx->aps_pAtpResp);
  2066. AtalkFreeMemory(pStsCtx);
  2067. }
  2068. }
  2069. LOCAL VOID
  2070. atalkAspCloseComplete(
  2071. IN ATALK_ERROR Status,
  2072. IN PASP_ADDROBJ pAspAddr
  2073. )
  2074. /*++
  2075. Routine Description:
  2076. Arguments:
  2077. Return Value:
  2078. --*/
  2079. {
  2080. DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
  2081. ("atalkAspCloseComplete: AtalkAtpCloseAddr returned %ld\n", Status));
  2082. AtalkAspDereferenceAddr(pAspAddr);
  2083. }
  2084. #if DBG
  2085. VOID
  2086. AtalkAspDumpSessions(
  2087. VOID
  2088. )
  2089. {
  2090. PASP_CONNOBJ pAspConn;
  2091. KIRQL OldIrql;
  2092. LONG i;
  2093. DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL, ("ASP SESSION LIST:\n"));
  2094. ACQUIRE_SPIN_LOCK(&atalkAspLock, &OldIrql);
  2095. for (i = 0; i < NUM_ASP_CONN_LISTS; i++)
  2096. {
  2097. for (pAspConn = atalkAspConnMaint[i].ascm_ConnList;
  2098. pAspConn != NULL;
  2099. pAspConn = pAspConn->aspco_NextSession)
  2100. {
  2101. DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
  2102. ("\tRemote Addr %4d.%3d.%2d SessionId %2d Flags %4x RefCount %ld\n",
  2103. pAspConn->aspco_WssRemoteAddr.ata_Network,
  2104. pAspConn->aspco_WssRemoteAddr.ata_Node,
  2105. pAspConn->aspco_WssRemoteAddr.ata_Socket,
  2106. pAspConn->aspco_SessionId,
  2107. pAspConn->aspco_Flags,
  2108. pAspConn->aspco_RefCount));
  2109. }
  2110. }
  2111. RELEASE_SPIN_LOCK(&atalkAspLock, OldIrql);
  2112. }
  2113. #endif
  2114.