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.

4889 lines
117 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. pap.c
  5. Abstract:
  6. This module implements the PAP 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 PAP
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(INIT, AtalkInitPapInitialize)
  19. #pragma alloc_text(PAGE_PAP, AtalkPapCreateAddress)
  20. #pragma alloc_text(PAGE_PAP, AtalkPapCreateConnection)
  21. #pragma alloc_text(PAGE_PAP, AtalkPapCleanupAddress)
  22. #pragma alloc_text(PAGE_PAP, AtalkPapCloseAddress)
  23. #pragma alloc_text(PAGE_PAP, AtalkPapCleanupConnection)
  24. #pragma alloc_text(PAGE_PAP, AtalkPapCloseConnection)
  25. #pragma alloc_text(PAGE_PAP, AtalkPapAssociateAddress)
  26. #pragma alloc_text(PAGE_PAP, AtalkPapDissociateAddress)
  27. #pragma alloc_text(PAGE_PAP, AtalkPapPostListen)
  28. #pragma alloc_text(PAGE_PAP, AtalkPapPrimeListener)
  29. #pragma alloc_text(PAGE_PAP, AtalkPapCancelListen)
  30. #pragma alloc_text(PAGE_PAP, AtalkPapPostConnect)
  31. #pragma alloc_text(PAGE_PAP, AtalkPapDisconnect)
  32. #pragma alloc_text(PAGE_PAP, AtalkPapRead)
  33. #pragma alloc_text(PAGE_PAP, AtalkPapPrimeRead)
  34. #pragma alloc_text(PAGE_PAP, AtalkPapWrite)
  35. #pragma alloc_text(PAGE_PAP, AtalkPapSetStatus)
  36. #pragma alloc_text(PAGE_PAP, AtalkPapGetStatus)
  37. #pragma alloc_text(PAGE_PAP, AtalkPapQuery)
  38. #pragma alloc_text(PAGE_PAP, atalkPapConnRefByPtrNonInterlock)
  39. #pragma alloc_text(PAGE_PAP, atalkPapConnRefByCtxNonInterlock)
  40. #pragma alloc_text(PAGE_PAP, atalkPapConnRefNextNc)
  41. #pragma alloc_text(PAGE_PAP, atalkPapPostSendDataResp)
  42. #pragma alloc_text(PAGE_PAP, atalkPapIncomingReadComplete)
  43. #pragma alloc_text(PAGE_PAP, atalkPapPrimedReadComplete)
  44. #pragma alloc_text(PAGE_PAP, atalkPapIncomingStatus)
  45. #pragma alloc_text(PAGE_PAP, atalkPapSendDataRel)
  46. #pragma alloc_text(PAGE_PAP, atalkPapSlsHandler)
  47. #pragma alloc_text(PAGE_PAP, atalkPapIncomingReq)
  48. #pragma alloc_text(PAGE_PAP, atalkPapIncomingOpenReply)
  49. #pragma alloc_text(PAGE_PAP, atalkPapIncomingRel)
  50. #pragma alloc_text(PAGE_PAP, atalkPapStatusRel)
  51. #pragma alloc_text(PAGE_PAP, atalkPapConnAccept)
  52. #pragma alloc_text(PAGE_PAP, atalkPapGetNextConnId)
  53. #pragma alloc_text(PAGE_PAP, atalkPapQueueAddrGlobalList)
  54. #pragma alloc_text(PAGE_PAP, atalkPapConnDeQueueAssocList)
  55. #pragma alloc_text(PAGE_PAP, atalkPapConnDeQueueConnectList)
  56. #pragma alloc_text(PAGE_PAP, atalkPapConnDeQueueListenList)
  57. #pragma alloc_text(PAGE_PAP, atalkPapConnDeQueueActiveList)
  58. #endif
  59. //
  60. // The model for PAP calls in this module is as follows:
  61. // - For create calls (CreateAddress & CreateSession), a pointer to the created
  62. // object is returned. This structure is referenced for creation.
  63. // - For all other calls, it expects a referenced pointer to the object.
  64. //
  65. VOID
  66. AtalkInitPapInitialize(
  67. VOID
  68. )
  69. /*++
  70. Routine Description:
  71. Arguments:
  72. Return Value:
  73. --*/
  74. {
  75. INITIALIZE_SPIN_LOCK(&atalkPapLock);
  76. AtalkTimerInitialize(&atalkPapCMTTimer,
  77. atalkPapConnMaintenanceTimer,
  78. PAP_CONNECTION_INTERVAL);
  79. AtalkTimerScheduleEvent(&atalkPapCMTTimer);
  80. }
  81. ATALK_ERROR
  82. AtalkPapCreateAddress(
  83. IN PATALK_DEV_CTX pDevCtx OPTIONAL,
  84. OUT PPAP_ADDROBJ * ppPapAddr
  85. )
  86. /*++
  87. Routine Description:
  88. Arguments:
  89. Return Value:
  90. --*/
  91. {
  92. PPAP_ADDROBJ pPapAddr = NULL;
  93. ATALK_ERROR error;
  94. do
  95. {
  96. // Allocate memory for the Pap address object
  97. if ((pPapAddr = AtalkAllocZeroedMemory(sizeof(PAP_ADDROBJ))) == NULL)
  98. {
  99. error = ATALK_RESR_MEM;
  100. break;
  101. }
  102. // Create an Atp Socket on the port for the Sls/Connection Socket.
  103. error = AtalkAtpOpenAddress(AtalkDefaultPort,
  104. 0,
  105. NULL,
  106. PAP_MAX_DATA_PACKET_SIZE,
  107. TRUE, // SEND_USER_BYTES_ALL
  108. NULL,
  109. FALSE, // CACHE address
  110. &pPapAddr->papao_pAtpAddr);
  111. if (!ATALK_SUCCESS(error))
  112. {
  113. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  114. ("AtalkPapCreateAddress: AtalkAtpOpenAddress fail %ld\n",error));
  115. break;
  116. }
  117. // Initialize the Pap address object
  118. pPapAddr->papao_Signature = PAPAO_SIGNATURE;
  119. INITIALIZE_SPIN_LOCK(&pPapAddr->papao_Lock);
  120. // Creation reference
  121. pPapAddr->papao_RefCount = 1;
  122. } while (FALSE);
  123. if (ATALK_SUCCESS(error))
  124. {
  125. // Insert into the global address list.
  126. atalkPapQueueAddrGlobalList(pPapAddr);
  127. *ppPapAddr = pPapAddr;
  128. }
  129. else if (pPapAddr != NULL)
  130. {
  131. AtalkFreeMemory(pPapAddr);
  132. }
  133. return error;
  134. }
  135. ATALK_ERROR
  136. AtalkPapCleanupAddress(
  137. IN PPAP_ADDROBJ pPapAddr
  138. )
  139. /*++
  140. Routine Description:
  141. Arguments:
  142. Return Value:
  143. --*/
  144. {
  145. PPAP_CONNOBJ pPapConn, pPapConnNext;
  146. KIRQL OldIrql;
  147. ATALK_ERROR error;
  148. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  149. ("AtalkPapCleanupAddress: %lx\n", pPapAddr));
  150. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  151. #if DBG
  152. pPapAddr->papao_Flags |= PAPAO_CLEANUP;
  153. #endif
  154. if ((pPapConn = pPapAddr->papao_pAssocConn) != NULL)
  155. {
  156. atalkPapConnRefNextNc(pPapConn, &pPapConnNext, &error);
  157. if (ATALK_SUCCESS(error))
  158. {
  159. while (TRUE)
  160. {
  161. if ((pPapConn = pPapConnNext) == NULL)
  162. {
  163. break;
  164. }
  165. if ((pPapConnNext = pPapConn->papco_pNextAssoc) != NULL)
  166. {
  167. atalkPapConnRefNextNc(pPapConnNext, &pPapConnNext, &error);
  168. if (!ATALK_SUCCESS(error))
  169. {
  170. pPapConnNext = NULL;
  171. }
  172. }
  173. // Shutdown this connection
  174. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  175. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  176. ("AtalkPapCloseAddress: Stopping conn %lx\n", pPapConn));
  177. AtalkPapCleanupConnection(pPapConn);
  178. AtalkPapConnDereference(pPapConn);
  179. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  180. }
  181. }
  182. }
  183. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  184. return ATALK_NO_ERROR;
  185. }
  186. ATALK_ERROR
  187. AtalkPapCloseAddress(
  188. IN PPAP_ADDROBJ pPapAddr,
  189. IN GENERIC_COMPLETION CompletionRoutine,
  190. IN PVOID pCloseCtx
  191. )
  192. /*++
  193. Routine Description:
  194. Arguments:
  195. Return Value:
  196. --*/
  197. {
  198. KIRQL OldIrql;
  199. PPAP_CONNOBJ pPapConn, pPapConnNext;
  200. DWORD dwAssocRefCounts=0;
  201. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  202. ("AtalkPapCloseAddress: %lx\n", pPapAddr));
  203. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  204. if (pPapAddr->papao_Flags & PAPAO_CLOSING)
  205. {
  206. // We are already closing! This should never happen!
  207. ASSERT(0);
  208. }
  209. pPapAddr->papao_Flags |= PAPAO_CLOSING;
  210. // Set the completion info.
  211. pPapAddr->papao_CloseComp = CompletionRoutine;
  212. pPapAddr->papao_CloseCtx = pCloseCtx;
  213. // Implicitly dissociate any connection objects
  214. for (pPapConn = pPapAddr->papao_pAssocConn;
  215. pPapConn != NULL;
  216. pPapConn = pPapConnNext)
  217. {
  218. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  219. pPapConnNext = pPapConn->papco_pNextAssoc;
  220. // when the conn was associate, we put a refcount: remove it
  221. if (pPapConn->papco_Flags & PAPCO_ADDR_ACTIVE)
  222. {
  223. pPapConn->papco_Flags &= ~PAPCO_ADDR_ACTIVE;
  224. dwAssocRefCounts++;
  225. }
  226. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  227. }
  228. ASSERT(pPapAddr->papao_CloseComp != NULL);
  229. ASSERT(pPapAddr->papao_CloseCtx != NULL);
  230. // ok to subtract: at least Creation refcount is still around
  231. pPapAddr->papao_RefCount -= dwAssocRefCounts;
  232. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  233. // Close the ATP Address Object.
  234. if (pPapAddr->papao_pAtpAddr != NULL)
  235. AtalkAtpCloseAddress(pPapAddr->papao_pAtpAddr, NULL, NULL);
  236. pPapAddr->papao_pAtpAddr = NULL;
  237. // Remove the creation reference count
  238. AtalkPapAddrDereference(pPapAddr);
  239. return ATALK_PENDING;
  240. }
  241. ATALK_ERROR
  242. AtalkPapCreateConnection(
  243. IN PVOID pConnCtx, // Context to associate with the session
  244. IN PATALK_DEV_CTX pDevCtx OPTIONAL,
  245. OUT PPAP_CONNOBJ * ppPapConn
  246. )
  247. /*++
  248. Routine Description:
  249. Create an PAP session. The created session starts off being an orphan, i.e.
  250. it has no parent address object. It gets one when it is associated.
  251. Arguments:
  252. Return Value:
  253. --*/
  254. {
  255. PPAP_CONNOBJ pPapConn;
  256. KIRQL OldIrql;
  257. // Allocate memory for a connection object
  258. if ((pPapConn = AtalkAllocZeroedMemory(sizeof(PAP_CONNOBJ))) == NULL)
  259. {
  260. return ATALK_RESR_MEM;
  261. }
  262. pPapConn->papco_Signature = PAPCO_SIGNATURE;
  263. INITIALIZE_SPIN_LOCK(&pPapConn->papco_Lock);
  264. pPapConn->papco_ConnCtx = pConnCtx;
  265. pPapConn->papco_Flags = 0;
  266. pPapConn->papco_RefCount = 1; // Creation reference
  267. pPapConn->papco_NextOutgoingSeqNum = 1; // Set to 1, not 0.
  268. pPapConn->papco_NextIncomingSeqNum = 1; // Next expected incoming.
  269. AtalkInitializeRT(&pPapConn->papco_RT,
  270. PAP_INIT_SENDDATA_REQ_INTERVAL,
  271. PAP_MIN_SENDDATA_REQ_INTERVAL,
  272. PAP_MAX_SENDDATA_REQ_INTERVAL);
  273. *ppPapConn = pPapConn;
  274. // Insert into the global connection list.
  275. ACQUIRE_SPIN_LOCK(&atalkPapLock, &OldIrql);
  276. AtalkLinkDoubleAtHead(atalkPapConnList, pPapConn, papco_Next, papco_Prev);
  277. RELEASE_SPIN_LOCK(&atalkPapLock, OldIrql);
  278. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  279. ("AtalkPapCreateConnection: %lx\n", pPapConn));
  280. return ATALK_NO_ERROR;
  281. }
  282. ATALK_ERROR
  283. AtalkPapCleanupConnection(
  284. IN PPAP_CONNOBJ pPapConn
  285. )
  286. /*++
  287. Routine Description:
  288. Shutdown a session.
  289. Arguments:
  290. Return Value:
  291. --*/
  292. {
  293. BOOLEAN stopping = FALSE;
  294. BOOLEAN pendingRead = FALSE;
  295. BOOLEAN fWaitingRead = FALSE;
  296. KIRQL OldIrql;
  297. ATALK_ERROR error = ATALK_NO_ERROR;
  298. ASSERT(VALID_PAPCO(pPapConn));
  299. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  300. ("AtalkPapCleanupConnection: %lx\n", pPapConn));
  301. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  302. pPapConn->papco_Flags |= PAPCO_LOCAL_DISCONNECT;
  303. #if DBG
  304. pPapConn->papco_Flags |= PAPCO_CLEANUP;
  305. #endif
  306. if ((pPapConn->papco_Flags & PAPCO_STOPPING) == 0)
  307. {
  308. // Allows completion of cleanup irp in Deref.
  309. pPapConn->papco_Flags |= PAPCO_STOPPING;
  310. // If already effectively stopped, just return.
  311. if (pPapConn->papco_Flags & PAPCO_ASSOCIATED)
  312. {
  313. pendingRead = (pPapConn->papco_Flags & PAPCO_READDATA_PENDING) ? TRUE : FALSE;
  314. if (pPapConn->papco_Flags & PAPCO_READDATA_WAITING)
  315. {
  316. fWaitingRead = TRUE;
  317. pPapConn->papco_Flags &= ~PAPCO_READDATA_WAITING;
  318. }
  319. ASSERTMSG("PapCleanup: Called with read data unread\n", !pendingRead);
  320. stopping = TRUE;
  321. }
  322. else
  323. {
  324. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  325. ("AtalkPapCleanupConnection: Called for a stopped conn %lx.%lx\n",
  326. pPapConn, pPapConn->papco_Flags));
  327. }
  328. }
  329. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  330. // Close the ATP Address Object if this was a server connection and
  331. // opened its own socket.
  332. if (stopping)
  333. {
  334. // If there is a pending read, then we need to cancel that atp request.
  335. if ((pendingRead || fWaitingRead) && (pPapConn->papco_pAtpAddr != NULL))
  336. {
  337. AtalkAtpCancelReq(pPapConn->papco_pAtpAddr,
  338. pPapConn->papco_ReadDataTid,
  339. &pPapConn->papco_RemoteAddr);
  340. }
  341. // If we are already disconnecting this will return an error which
  342. // we ignore. But if we were only in the ASSOCIATED state, then we
  343. // need to call disassociate here.
  344. error = AtalkPapDisconnect(pPapConn,
  345. ATALK_LOCAL_DISCONNECT,
  346. NULL,
  347. NULL);
  348. // We were already disconnected.
  349. if (error == ATALK_INVALID_REQUEST)
  350. {
  351. AtalkPapDissociateAddress(pPapConn);
  352. }
  353. }
  354. return ATALK_NO_ERROR;
  355. }
  356. ATALK_ERROR
  357. AtalkPapCloseConnection(
  358. IN PPAP_CONNOBJ pPapConn,
  359. IN GENERIC_COMPLETION CompletionRoutine,
  360. IN PVOID pCloseCtx
  361. )
  362. /*++
  363. Routine Description:
  364. Shutdown a session.
  365. Arguments:
  366. Return Value:
  367. --*/
  368. {
  369. KIRQL OldIrql;
  370. ASSERT(VALID_PAPCO(pPapConn));
  371. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  372. ("AtalkPapCloseConnection: %lx\n", pPapConn));
  373. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  374. if (pPapConn->papco_Flags & PAPCO_CLOSING)
  375. {
  376. // We are already closing! This should never happen!
  377. KeBugCheck(0);
  378. }
  379. pPapConn->papco_Flags |= PAPCO_CLOSING;
  380. // Set the completion info.
  381. pPapConn->papco_CloseComp = CompletionRoutine;
  382. pPapConn->papco_CloseCtx = pCloseCtx;
  383. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  384. // Remove the creation reference count
  385. AtalkPapConnDereference(pPapConn);
  386. return ATALK_PENDING;
  387. }
  388. ATALK_ERROR
  389. AtalkPapAssociateAddress(
  390. IN PPAP_ADDROBJ pPapAddr,
  391. IN PPAP_CONNOBJ pPapConn
  392. )
  393. /*++
  394. Routine Description:
  395. Removed reference for the address for this connection. Causes deadlock in AFD where
  396. AFD blocks on close of the address object and we wait for connections to be closed
  397. first
  398. Arguments:
  399. Return Value:
  400. --*/
  401. {
  402. ATALK_ERROR error;
  403. KIRQL OldIrql;
  404. ASSERT(VALID_PAPAO(pPapAddr));
  405. ASSERT(VALID_PAPCO(pPapConn));
  406. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  407. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  408. error = ATALK_ALREADY_ASSOCIATED;
  409. if ((pPapConn->papco_Flags & PAPCO_ASSOCIATED) == 0)
  410. {
  411. error = ATALK_NO_ERROR;
  412. // Link it in.
  413. pPapConn->papco_pNextAssoc = pPapAddr->papao_pAssocConn;
  414. pPapAddr->papao_pAssocConn = pPapConn;
  415. // Remove not associated flag.
  416. pPapConn->papco_Flags |= PAPCO_ASSOCIATED;
  417. pPapConn->papco_pAssocAddr = pPapAddr;
  418. // put Association refcount
  419. pPapAddr->papao_RefCount++;
  420. // mark that fact that we now have a refcount on addr obj for this conn
  421. pPapConn->papco_Flags |= PAPCO_ADDR_ACTIVE;
  422. }
  423. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  424. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  425. return error;
  426. }
  427. ATALK_ERROR
  428. AtalkPapDissociateAddress(
  429. IN PPAP_CONNOBJ pPapConn
  430. )
  431. /*++
  432. Routine Description:
  433. Arguments:
  434. Return Value:
  435. --*/
  436. {
  437. PPAP_ADDROBJ pPapAddr;
  438. KIRQL OldIrql;
  439. ATALK_ERROR error = ATALK_NO_ERROR;
  440. BOOLEAN fDerefAddr = FALSE;
  441. ASSERT(VALID_PAPCO(pPapConn));
  442. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  443. if ((pPapConn->papco_Flags & (PAPCO_LISTENING |
  444. PAPCO_CONNECTING |
  445. PAPCO_ACTIVE |
  446. PAPCO_ASSOCIATED)) != PAPCO_ASSOCIATED)
  447. {
  448. error = ATALK_INVALID_CONNECTION;
  449. }
  450. else
  451. {
  452. pPapAddr = pPapConn->papco_pAssocAddr ;
  453. ASSERT(VALID_PAPAO(pPapAddr));
  454. // Set not associated flag.
  455. pPapConn->papco_Flags &= ~PAPCO_ASSOCIATED;
  456. pPapConn->papco_pAssocAddr = NULL;
  457. if (pPapConn->papco_Flags & PAPCO_ADDR_ACTIVE)
  458. {
  459. pPapConn->papco_Flags &= ~PAPCO_ADDR_ACTIVE;
  460. fDerefAddr = TRUE;
  461. }
  462. }
  463. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  464. // Unlink it if ok.
  465. if (ATALK_SUCCESS(error))
  466. {
  467. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  468. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  469. atalkPapConnDeQueueAssocList(pPapAddr, pPapConn);
  470. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  471. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  472. if (fDerefAddr)
  473. {
  474. // remove the Association refcount
  475. AtalkPapAddrDereference(pPapAddr);
  476. }
  477. }
  478. return error;
  479. }
  480. ATALK_ERROR
  481. AtalkPapPostListen(
  482. IN PPAP_CONNOBJ pPapConn,
  483. IN PVOID pListenCtx,
  484. IN GENERIC_COMPLETION CompletionRoutine
  485. )
  486. /*++
  487. Routine Description:
  488. Arguments:
  489. Return Value:
  490. --*/
  491. {
  492. PPAP_ADDROBJ pPapAddr = pPapConn->papco_pAssocAddr;
  493. KIRQL OldIrql;
  494. ATALK_ERROR error;
  495. // This will also insert the connection object in the address objects
  496. // list of connection which have a listen posted on them. When open
  497. // connection requests come in, the first connection is taken off the list
  498. // and the request satisfied.
  499. ASSERT(VALID_PAPCO(pPapConn));
  500. ASSERT(VALID_PAPAO(pPapAddr));
  501. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  502. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  503. do
  504. {
  505. if ((pPapConn->papco_Flags & (PAPCO_LISTENING |
  506. PAPCO_CONNECTING |
  507. PAPCO_ACTIVE |
  508. PAPCO_ASSOCIATED)) != PAPCO_ASSOCIATED)
  509. {
  510. error = ATALK_INVALID_CONNECTION;
  511. break;
  512. }
  513. // Verify the address object is not a connect address type.
  514. if (pPapAddr->papao_Flags & PAPAO_CONNECT)
  515. {
  516. error = ATALK_INVALID_PARAMETER;
  517. break;
  518. }
  519. // Make the address object a listener.
  520. pPapAddr->papao_Flags |= PAPAO_LISTENER;
  521. pPapConn->papco_Flags |= PAPCO_LISTENING;
  522. pPapConn->papco_ListenCtx = pListenCtx;
  523. pPapConn->papco_ListenCompletion = CompletionRoutine;
  524. // Insert into the listen list.
  525. pPapConn->papco_pNextListen = pPapAddr->papao_pListenConn;
  526. pPapAddr->papao_pListenConn = pPapConn;
  527. // Unblock the address object.
  528. pPapAddr->papao_Flags |= PAPAO_UNBLOCKED;
  529. error = ATALK_NO_ERROR;
  530. } while (FALSE);
  531. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  532. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  533. if (ATALK_SUCCESS(error))
  534. {
  535. // Now enqueue a few handlers on the address object. These will handle
  536. // open conn/get status etc.
  537. //
  538. // DOC: For our implementation, until a server associates and places a
  539. // listen on one of the connection objects, we do not become a
  540. // listener. So the fact that we will not handle any request
  541. // until that point is ok. Note that for a connect, the requests
  542. // get posted on the connections atp address, which will be the same
  543. // as the address's atp address.
  544. if (!ATALK_SUCCESS(error = AtalkPapPrimeListener(pPapAddr)))
  545. {
  546. // Undo insert into the listen list.
  547. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  548. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  549. atalkPapConnDeQueueListenList(pPapAddr, pPapConn);
  550. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  551. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  552. }
  553. }
  554. return error;
  555. }
  556. ATALK_ERROR
  557. AtalkPapPrimeListener(
  558. IN PPAP_ADDROBJ pPapAddr
  559. )
  560. /*++
  561. Routine Description:
  562. Enqueue a handler on the listener.
  563. Arguments:
  564. Return Value:
  565. --*/
  566. {
  567. ATALK_ERROR error = ATALK_NO_ERROR;
  568. KIRQL OldIrql;
  569. BOOLEAN Unlock = TRUE;
  570. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  571. if ((pPapAddr->papao_Flags & PAPAO_SLS_QUEUED) == 0)
  572. {
  573. // Reference the address object for this handler we will be enqueuing.
  574. AtalkPapAddrReferenceNonInterlock(pPapAddr, &error);
  575. if (ATALK_SUCCESS(error))
  576. {
  577. pPapAddr->papao_Flags |= PAPAO_SLS_QUEUED;
  578. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  579. Unlock = FALSE;
  580. AtalkAtpSetReqHandler(pPapAddr->papao_pAtpAddr,
  581. atalkPapSlsHandler,
  582. pPapAddr);
  583. }
  584. }
  585. if (Unlock)
  586. {
  587. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  588. }
  589. return error;
  590. }
  591. ATALK_ERROR
  592. AtalkPapCancelListen(
  593. IN PPAP_CONNOBJ pPapConn
  594. )
  595. /*++
  596. Routine Description:
  597. Cancel a previously posted listen.
  598. Arguments:
  599. Return Value:
  600. --*/
  601. {
  602. PPAP_ADDROBJ pPapAddr = pPapConn->papco_pAssocAddr;
  603. ATALK_ERROR error = ATALK_NO_ERROR;
  604. GENERIC_COMPLETION completionRoutine = NULL;
  605. KIRQL OldIrql;
  606. PVOID completionCtx = NULL;
  607. ASSERT(VALID_PAPCO(pPapConn));
  608. ASSERT(VALID_PAPAO(pPapAddr));
  609. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  610. if (!atalkPapConnDeQueueListenList(pPapAddr, pPapConn))
  611. {
  612. error = ATALK_INVALID_CONNECTION;
  613. }
  614. else
  615. {
  616. // We complete the listen routine
  617. ASSERT(pPapConn->papco_Flags & PAPCO_LISTENING);
  618. pPapConn->papco_Flags &= ~PAPCO_LISTENING;
  619. completionRoutine = pPapConn->papco_ListenCompletion;
  620. completionCtx = pPapConn->papco_ListenCtx;
  621. }
  622. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  623. if (*completionRoutine != NULL)
  624. {
  625. (*completionRoutine)(ATALK_REQUEST_CANCELLED, completionCtx);
  626. }
  627. return error;
  628. }
  629. ATALK_ERROR
  630. AtalkPapPostConnect(
  631. IN PPAP_CONNOBJ pPapConn,
  632. IN PATALK_ADDR pRemoteAddr,
  633. IN PVOID pConnectCtx,
  634. IN GENERIC_COMPLETION CompletionRoutine
  635. )
  636. /*++
  637. Routine Description:
  638. Arguments:
  639. Return Value:
  640. --*/
  641. {
  642. BOOLEAN DerefConn = FALSE;
  643. KIRQL OldIrql;
  644. ATALK_ERROR error = ATALK_NO_ERROR;
  645. PBYTE pOpenPkt = NULL, pRespPkt = NULL;
  646. PAMDL pOpenAmdl = NULL, pRespAmdl = NULL;
  647. PPAP_ADDROBJ pPapAddr = pPapConn->papco_pAssocAddr;
  648. ASSERT(VALID_PAPAO(pPapAddr));
  649. ASSERT(VALID_PAPCO(pPapConn));
  650. // Allocate a buffer to use.
  651. if (((pOpenPkt = AtalkAllocMemory(PAP_STATUS_OFF)) == NULL) ||
  652. ((pOpenAmdl = AtalkAllocAMdl(pOpenPkt, PAP_STATUS_OFF)) == NULL) ||
  653. ((pRespPkt = AtalkAllocMemory(PAP_MAX_DATA_PACKET_SIZE)) == NULL) ||
  654. ((pRespAmdl = AtalkAllocAMdl(pRespPkt, PAP_MAX_DATA_PACKET_SIZE)) == NULL))
  655. {
  656. if (pOpenPkt != NULL)
  657. AtalkFreeMemory(pOpenPkt);
  658. if (pOpenAmdl != NULL)
  659. AtalkFreeAMdl(pOpenAmdl);
  660. if (pRespPkt != NULL)
  661. AtalkFreeMemory(pRespPkt);
  662. return ATALK_RESR_MEM;
  663. }
  664. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  665. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  666. do
  667. {
  668. if ((pPapConn->papco_Flags & (PAPCO_LISTENING |
  669. PAPCO_CONNECTING |
  670. PAPCO_ACTIVE |
  671. PAPCO_ASSOCIATED)) != PAPCO_ASSOCIATED)
  672. {
  673. error = ATALK_INVALID_CONNECTION;
  674. break;
  675. }
  676. // Verify the address object is not a listener address type.
  677. if (pPapAddr->papao_Flags & PAPAO_LISTENER)
  678. {
  679. error = ATALK_INVALID_ADDRESS;
  680. break;
  681. }
  682. // Reference the connection for the request we will be posting
  683. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  684. if (!ATALK_SUCCESS(error))
  685. {
  686. ASSERTMSG("AtalkPapPostConnect: Connection ref failed\n", 0);
  687. break;
  688. }
  689. DerefConn = TRUE;
  690. pPapConn->papco_ConnId = atalkPapGetNextConnId(pPapAddr, &error);
  691. if (ATALK_SUCCESS(error))
  692. {
  693. // Make sure flags are clean.
  694. pPapConn->papco_Flags &= ~(PAPCO_SENDDATA_RECD |
  695. PAPCO_WRITEDATA_WAITING |
  696. PAPCO_SEND_EOF_WRITE |
  697. PAPCO_READDATA_PENDING |
  698. PAPCO_REMOTE_CLOSE |
  699. PAPCO_NONBLOCKING_READ |
  700. PAPCO_READDATA_WAITING);
  701. pPapConn->papco_Flags |= PAPCO_CONNECTING;
  702. pPapConn->papco_ConnectCtx = pConnectCtx;
  703. pPapConn->papco_ConnectCompletion = CompletionRoutine;
  704. pPapConn->papco_pConnectRespBuf = pRespPkt;
  705. pPapConn->papco_pConnectOpenBuf = pOpenPkt;
  706. pPapConn->papco_ConnectRespLen = PAP_MAX_DATA_PACKET_SIZE;
  707. pPapConn->papco_RemoteAddr = *pRemoteAddr;
  708. pPapConn->papco_WaitTimeOut = 0; // To begin with
  709. // For CONNECT, the connection object inherits the associated
  710. // address objects atp address.
  711. pPapConn->papco_pAtpAddr = pPapAddr->papao_pAtpAddr;
  712. // Insert into the connect list.
  713. pPapConn->papco_pNextConnect = pPapAddr->papao_pConnectConn;
  714. pPapAddr->papao_pConnectConn = pPapConn;
  715. pPapAddr->papao_Flags |= PAPAO_CONNECT;
  716. }
  717. else
  718. {
  719. ASSERTMSG("AtalkPapPostConnect: Unable to get conn id > 255 sess?\n", 0);
  720. }
  721. } while (FALSE);
  722. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  723. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  724. if (ATALK_SUCCESS(error))
  725. {
  726. error = atalkPapRepostConnect(pPapConn, pOpenAmdl, pRespAmdl);
  727. if (ATALK_SUCCESS(error))
  728. {
  729. error = ATALK_PENDING;
  730. DerefConn = FALSE;
  731. }
  732. else
  733. {
  734. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  735. ("AtalkPapConnect: AtalkAtpPostReq: failed %ld\n", error));
  736. // Remove connection from the connect list and reset states.
  737. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  738. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  739. pPapConn->papco_Flags &= ~PAPCO_CONNECTING;
  740. pPapConn->papco_ConnectCtx = NULL;
  741. pPapConn->papco_ConnectCompletion = NULL;
  742. pPapConn->papco_pConnectRespBuf = NULL;
  743. pPapConn->papco_ConnectRespLen = 0;
  744. pPapConn->papco_pAtpAddr = NULL;
  745. // Remove from the connect list.
  746. atalkPapConnDeQueueConnectList(pPapAddr, pPapConn);
  747. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  748. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  749. }
  750. }
  751. if (!ATALK_SUCCESS(error))
  752. {
  753. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  754. ("AtalkPapConnect: failed %ld\n", error));
  755. // Free all buffers.
  756. ASSERT(pOpenPkt != NULL);
  757. AtalkFreeMemory(pOpenPkt);
  758. ASSERT(pOpenAmdl != NULL);
  759. AtalkFreeAMdl(pOpenAmdl);
  760. ASSERT(pRespPkt != NULL);
  761. AtalkFreeMemory(pRespPkt);
  762. ASSERT(pRespAmdl != NULL);
  763. AtalkFreeAMdl(pRespAmdl);
  764. }
  765. if (DerefConn)
  766. {
  767. AtalkPapConnDereference(pPapConn);
  768. }
  769. return error;
  770. }
  771. ATALK_ERROR
  772. AtalkPapDisconnect(
  773. IN PPAP_CONNOBJ pPapConn,
  774. IN ATALK_DISCONNECT_TYPE DisconnectType,
  775. IN PVOID pDisconnectCtx,
  776. IN GENERIC_COMPLETION CompletionRoutine
  777. )
  778. /*++
  779. Routine Description:
  780. Arguments:
  781. Return Value:
  782. --*/
  783. {
  784. ATALK_ERROR tmpError;
  785. PACTREQ pActReq;
  786. PAMDL writeBuf;
  787. PVOID writeCtx;
  788. GENERIC_WRITE_COMPLETION writeCompletion = NULL;
  789. ATALK_ERROR error = ATALK_PENDING;
  790. KIRQL OldIrql;
  791. BOOLEAN cancelPrimedRead = FALSE;
  792. ASSERT(VALID_PAPCO(pPapConn));
  793. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  794. ("AtalkPapDisconnect: %lx.%lx\n", pPapConn, DisconnectType));
  795. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  796. // is it already disconnecting?
  797. if (pPapConn->papco_Flags & PAPCO_DISCONNECTING)
  798. {
  799. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  800. return(ATALK_PAP_CONN_CLOSING);
  801. }
  802. // When a disconnect comes in, we abort any sends waiting for a remote
  803. // send data to come in.
  804. if ((pPapConn->papco_Flags & (PAPCO_WRITEDATA_WAITING|PAPCO_SENDDATA_RECD)) ==
  805. PAPCO_WRITEDATA_WAITING)
  806. {
  807. // In this situation, what happened is that a write was posted
  808. // before a send data was received. As PapPostSendData response
  809. // was never called in that case, there will be no pending reference
  810. // on the connection.
  811. writeCompletion = pPapConn->papco_WriteCompletion;
  812. writeCtx = pPapConn->papco_WriteCtx;
  813. writeBuf = pPapConn->papco_pWriteBuf;
  814. pPapConn->papco_Flags &= ~PAPCO_WRITEDATA_WAITING;
  815. pPapConn->papco_WriteCtx = NULL;
  816. pPapConn->papco_pWriteBuf= NULL;
  817. pPapConn->papco_WriteCompletion = NULL;
  818. }
  819. // Handle the case where a send data was received, but no data is to be sent
  820. // just cancel the response.
  821. if (pPapConn->papco_Flags & PAPCO_SENDDATA_RECD)
  822. {
  823. PATP_RESP pAtpResp = pPapConn->papco_pAtpResp;
  824. ASSERT(VALID_ATPRS(pAtpResp));
  825. pPapConn->papco_Flags &= ~PAPCO_SENDDATA_RECD;
  826. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  827. AtalkAtpCancelResp(pAtpResp);
  828. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  829. }
  830. // Handle the race condition between disconnect and last recv. indication.
  831. // The fact that we have received a disconnect from the other side implies
  832. // that we have sent out a release which in turn implies that we have all
  833. // the data. If this is the case, then we defer disconnect till the recv.
  834. // indication is done. Otherwise AFD gets real upset.
  835. if ((DisconnectType == ATALK_REMOTE_DISCONNECT) &&
  836. (pPapConn->papco_Flags & PAPCO_NONBLOCKING_READ))
  837. {
  838. if (AtalkAtpIsReqComplete(pPapConn->papco_pAtpAddr,
  839. pPapConn->papco_ReadDataTid,
  840. &pPapConn->papco_RemoteAddr))
  841. {
  842. pPapConn->papco_Flags |= PAPCO_DELAYED_DISCONNECT;
  843. }
  844. }
  845. // Support for graceful disconnect. We only drop the received
  846. // data when the local end does a disconnect. This will happen
  847. // regardless of whether this routine was previously called or
  848. // not. Also, this means that we must satisfy a read if disconnect is pending.
  849. if ((DisconnectType == ATALK_LOCAL_DISCONNECT) ||
  850. (DisconnectType == ATALK_TIMER_DISCONNECT))
  851. {
  852. pPapConn->papco_Flags |= PAPCO_REJECT_READS;
  853. if (pPapConn->papco_Flags & PAPCO_READDATA_WAITING)
  854. {
  855. ASSERT(pPapConn->papco_Flags & PAPCO_NONBLOCKING_READ);
  856. pActReq = pPapConn->papco_NbReadActReq;
  857. // Reset the flags
  858. pPapConn->papco_Flags &= ~(PAPCO_NONBLOCKING_READ | PAPCO_READDATA_WAITING);
  859. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  860. // Call the action completion routine for the prime read.
  861. (*pActReq->ar_Completion)(ATALK_LOCAL_CLOSE, pActReq);
  862. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  863. }
  864. }
  865. if ((pPapConn->papco_Flags & (PAPCO_DISCONNECTING | PAPCO_DELAYED_DISCONNECT)) == 0)
  866. {
  867. if (pPapConn->papco_Flags & (PAPCO_LISTENING |
  868. PAPCO_CONNECTING |
  869. PAPCO_ACTIVE))
  870. {
  871. pPapConn->papco_Flags |= PAPCO_DISCONNECTING;
  872. if (pPapConn->papco_Flags & PAPCO_LISTENING)
  873. {
  874. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  875. AtalkPapCancelListen(pPapConn);
  876. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  877. }
  878. else if (pPapConn->papco_Flags & PAPCO_CONNECTING)
  879. {
  880. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  881. tmpError = AtalkAtpCancelReq(pPapConn->papco_pAtpAddr,
  882. pPapConn->papco_ConnectTid,
  883. &pPapConn->papco_RemoteAddr);
  884. // We just stop the address. If success, it'll be dequeued from the
  885. // connect list. If !success, its gone active. In either
  886. // case we do not need to cleanup the ATP address. It could
  887. // possibly be set to NULL by now as disconnect would have
  888. // completed.
  889. if (ATALK_SUCCESS(tmpError))
  890. {
  891. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  892. ("atalkPapDisconnect: Stopping atp address for %lx\n", pPapConn));
  893. // AtalkAtpCleanupAddress(pPapConn->papco_pAtpAddr);
  894. }
  895. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  896. }
  897. // Both of the above could have failed as the connection
  898. // might have become active before the cancel succeeded.
  899. // In that case (or if we were active to begin with), do
  900. // a disconnect here.
  901. if (pPapConn->papco_Flags & PAPCO_ACTIVE)
  902. {
  903. // Remember completion routines as appropriate.
  904. if (DisconnectType == ATALK_INDICATE_DISCONNECT)
  905. {
  906. if (pPapConn->papco_DisconnectInform == NULL)
  907. {
  908. pPapConn->papco_DisconnectInform = CompletionRoutine;
  909. pPapConn->papco_DisconnectInformCtx = pDisconnectCtx;
  910. }
  911. else
  912. {
  913. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  914. ("AtalkPapDisconnect: duplicate disc comp rou%lx\n", pPapConn));
  915. error = ATALK_TOO_MANY_COMMANDS;
  916. }
  917. }
  918. else if (DisconnectType == ATALK_LOCAL_DISCONNECT)
  919. {
  920. // Replace completion routines only if previous ones are NULL.
  921. if (pPapConn->papco_DisconnectCompletion == NULL)
  922. {
  923. pPapConn->papco_DisconnectCompletion = CompletionRoutine;
  924. pPapConn->papco_DisconnectCtx = pDisconnectCtx;
  925. }
  926. else
  927. {
  928. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  929. ("AtalkPapDisconnect: duplicate disc comp rou%lx\n", pPapConn));
  930. error = ATALK_TOO_MANY_COMMANDS;
  931. }
  932. }
  933. // Figure out the disconnect status and remember it in the
  934. // connection object.
  935. pPapConn->papco_DisconnectStatus = DISCONN_STATUS(DisconnectType);
  936. if ((pPapConn->papco_Flags & (PAPCO_NONBLOCKING_READ|PAPCO_READDATA_WAITING)) ==
  937. PAPCO_NONBLOCKING_READ)
  938. {
  939. pPapConn->papco_Flags &= ~PAPCO_NONBLOCKING_READ;
  940. cancelPrimedRead = TRUE;
  941. }
  942. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  943. // If there is a pending write, then we need to complete the write.
  944. if (writeCompletion != NULL)
  945. {
  946. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  947. ("AtalkPapDisconect: Completing write %lx.%lx\n",
  948. pPapConn, pPapConn->papco_DisconnectStatus));
  949. (*writeCompletion)(pPapConn->papco_DisconnectStatus,
  950. writeBuf,
  951. 0, // Write length
  952. writeCtx);
  953. }
  954. if (cancelPrimedRead)
  955. {
  956. AtalkAtpCancelReq(pPapConn->papco_pAtpAddr,
  957. pPapConn->papco_ReadDataTid,
  958. &pPapConn->papco_RemoteAddr);
  959. }
  960. // Cancel the tickle request
  961. AtalkAtpCancelReq(pPapConn->papco_pAtpAddr,
  962. pPapConn->papco_TickleTid,
  963. &pPapConn->papco_RemoteAddr);
  964. // Send out disconnect packet if this was a timer or local close.
  965. if ((DisconnectType == ATALK_LOCAL_DISCONNECT) ||
  966. (DisconnectType == ATALK_TIMER_DISCONNECT))
  967. {
  968. BYTE userBytes[ATP_USERBYTES_SIZE];
  969. USHORT tid;
  970. userBytes[PAP_CONNECTIONID_OFF] = pPapConn->papco_ConnId;
  971. userBytes[PAP_CMDTYPE_OFF] = PAP_CLOSE_CONN;
  972. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], 0);
  973. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  974. ("AtalkPapDisconect: Sending disc to %lx - %lx\n",
  975. pPapConn->papco_RemoteAddr.ata_Address,
  976. DisconnectType));
  977. tmpError = AtalkAtpPostReq(pPapConn->papco_pAtpAddr,
  978. &pPapConn->papco_RemoteAddr,
  979. &tid,
  980. 0, // ALO request
  981. NULL,
  982. 0,
  983. userBytes,
  984. NULL,
  985. 0,
  986. 0, // Retry count
  987. 0, // Retry interval
  988. THIRTY_SEC_TIMER,
  989. NULL,
  990. NULL);
  991. if (!ATALK_SUCCESS(tmpError))
  992. {
  993. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  994. ("AtalkPapDisconnect: post disc to rem fail%lx\n", pPapConn));
  995. }
  996. }
  997. // Call the disconnect indication routine if present for a timer/
  998. // remote disconnect.
  999. if ((DisconnectType == ATALK_REMOTE_DISCONNECT) ||
  1000. (DisconnectType == ATALK_TIMER_DISCONNECT))
  1001. {
  1002. PVOID discCtx;
  1003. PTDI_IND_DISCONNECT discHandler = NULL;
  1004. // Acquire lock so we get a consistent handler/ctx.
  1005. ACQUIRE_SPIN_LOCK(&pPapConn->papco_pAssocAddr->papao_Lock, &OldIrql);
  1006. discHandler = pPapConn->papco_pAssocAddr->papao_DisconnectHandler;
  1007. discCtx = pPapConn->papco_pAssocAddr->papao_DisconnectHandlerCtx;
  1008. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1009. ("AtalkPapDisconnect: IndDisc to AFD %lx\n", pPapConn));
  1010. #if DBG
  1011. if (discHandler != NULL)
  1012. {
  1013. pPapConn->papco_Flags |= PAPCO_INDICATE_AFD_DISC;
  1014. }
  1015. #endif
  1016. RELEASE_SPIN_LOCK(&pPapConn->papco_pAssocAddr->papao_Lock, OldIrql);
  1017. if (discHandler != NULL)
  1018. {
  1019. // We use TDI_DISCONNECT_ABORT for flags. This makes
  1020. // AFD call Close for connection, but also allows a
  1021. // recv to come in as we are a buffering transport.
  1022. (*discHandler)(discCtx,
  1023. pPapConn->papco_ConnCtx,
  1024. 0, // DisconnectDataLength
  1025. NULL, // DisconnectData
  1026. 0, // DisconnectInfoLength
  1027. NULL, // DisconnectInfo
  1028. TDI_DISCONNECT_ABORT); // Disconnect flags.
  1029. }
  1030. }
  1031. // Stop the atp address. only if we are a server job ?
  1032. // Client side pap connections can be many-to-one atp address.
  1033. // Doesn't affect monitor.
  1034. AtalkAtpCleanupAddress(pPapConn->papco_pAtpAddr);
  1035. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1036. }
  1037. }
  1038. else
  1039. {
  1040. error = ATALK_INVALID_REQUEST;
  1041. }
  1042. }
  1043. else
  1044. {
  1045. // Do we need to remember the completion routines?
  1046. // Yes, if this is a disconnect or a indicate disconnect request,
  1047. // and our current disconnect was started due to the address object
  1048. // being closed.
  1049. if (DisconnectType == ATALK_INDICATE_DISCONNECT)
  1050. {
  1051. if (pPapConn->papco_DisconnectInform == NULL)
  1052. {
  1053. pPapConn->papco_DisconnectInform = CompletionRoutine;
  1054. pPapConn->papco_DisconnectInformCtx = pDisconnectCtx;
  1055. }
  1056. else
  1057. {
  1058. error = ATALK_TOO_MANY_COMMANDS;
  1059. }
  1060. }
  1061. else if (DisconnectType == ATALK_LOCAL_DISCONNECT)
  1062. {
  1063. // Replace completion routines only if previous ones are NULL.
  1064. if (pPapConn->papco_DisconnectCompletion == NULL)
  1065. {
  1066. pPapConn->papco_DisconnectCompletion = CompletionRoutine;
  1067. pPapConn->papco_DisconnectCtx = pDisconnectCtx;
  1068. }
  1069. else
  1070. {
  1071. error = ATALK_TOO_MANY_COMMANDS;
  1072. }
  1073. }
  1074. }
  1075. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1076. return error;
  1077. }
  1078. ATALK_ERROR
  1079. AtalkPapRead(
  1080. IN PPAP_CONNOBJ pPapConn,
  1081. IN PAMDL pReadBuf,
  1082. IN USHORT ReadBufLen,
  1083. IN ULONG ReadFlags,
  1084. IN PVOID pReadCtx,
  1085. IN GENERIC_READ_COMPLETION CompletionRoutine
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. Arguments:
  1090. Return Value:
  1091. --*/
  1092. {
  1093. BYTE userBytes[ATP_USERBYTES_SIZE];
  1094. USHORT readLen, timeout;
  1095. ULONG readFlags;
  1096. PACTREQ pActReq;
  1097. BOOLEAN delayedDisConn = FALSE;
  1098. KIRQL OldIrql;
  1099. ATALK_ERROR error = ATALK_NO_ERROR;
  1100. ASSERT(VALID_PAPCO(pPapConn));
  1101. ASSERT(*CompletionRoutine != NULL);
  1102. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1103. do
  1104. {
  1105. if (ReadFlags & TDI_RECEIVE_EXPEDITED)
  1106. {
  1107. error = ATALK_INVALID_PARAMETER;
  1108. break;
  1109. }
  1110. if (pPapConn->papco_Flags & PAPCO_READDATA_PENDING)
  1111. {
  1112. error = ATALK_PAP_TOO_MANY_READS;
  1113. break;
  1114. }
  1115. // PEEK not supported for PAP
  1116. if (ReadFlags & TDI_RECEIVE_PEEK)
  1117. {
  1118. error = ATALK_PAP_INVALID_REQUEST;
  1119. break;
  1120. }
  1121. // Do we already have a pending/indicated read waiting?
  1122. // !!!NOTE!!! If we do we complete the read regardless. With winsock
  1123. // our primed read will complete and we will indicate the data, but the
  1124. // mac immediately follows with a disconnect. if the winsock client is
  1125. // unable to read the data, before the disconnect comes in, it will lose
  1126. // the last block of data.
  1127. if (pPapConn->papco_Flags & PAPCO_READDATA_WAITING)
  1128. {
  1129. pActReq = pPapConn->papco_NbReadActReq;
  1130. readLen = pPapConn->papco_NbReadLen;
  1131. readFlags = pPapConn->papco_NbReadFlags;
  1132. // Make sure buffer size is atleast that of the indicated
  1133. // data.
  1134. if (ReadBufLen < readLen)
  1135. {
  1136. error = ATALK_BUFFER_TOO_SMALL;
  1137. break;
  1138. }
  1139. // Reset the flags allowing primes to happen.
  1140. pPapConn->papco_Flags &= ~(PAPCO_NONBLOCKING_READ |
  1141. PAPCO_READDATA_WAITING);
  1142. pPapConn->papco_NbReadLen = 0;
  1143. pPapConn->papco_NbReadFlags = 0;
  1144. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1145. // Call the action completion routine for the prime read.
  1146. (*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq);
  1147. if (ATALK_SUCCESS(error))
  1148. {
  1149. error = ((readFlags & TDI_RECEIVE_PARTIAL) ?
  1150. ATALK_PAP_PARTIAL_RECEIVE : ATALK_NO_ERROR);
  1151. }
  1152. // Call completion routine and return status success.
  1153. (*CompletionRoutine)(error,
  1154. pReadBuf,
  1155. readLen,
  1156. readFlags,
  1157. pReadCtx);
  1158. // Return pending.
  1159. return ATALK_PENDING;
  1160. }
  1161. if ((pPapConn->papco_Flags & PAPCO_ACTIVE) == 0)
  1162. {
  1163. error = ATALK_PAP_CONN_NOT_ACTIVE;
  1164. break;
  1165. }
  1166. if (ReadBufLen < (PAP_MAX_FLOW_QUANTUM*PAP_MAX_DATA_PACKET_SIZE))
  1167. {
  1168. error = ATALK_BUFFER_TOO_SMALL;
  1169. break;
  1170. }
  1171. error = ATALK_INVALID_CONNECTION;
  1172. if ((pPapConn->papco_Flags & (PAPCO_CLOSING |
  1173. PAPCO_STOPPING |
  1174. PAPCO_DISCONNECTING)) == 0)
  1175. {
  1176. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  1177. }
  1178. if (!ATALK_SUCCESS(error))
  1179. {
  1180. break;
  1181. }
  1182. pPapConn->papco_Flags |= PAPCO_READDATA_PENDING;
  1183. // Remember read information in the connection object.
  1184. pPapConn->papco_ReadCompletion = CompletionRoutine;
  1185. pPapConn->papco_ReadCtx = pReadCtx;
  1186. } while (FALSE);
  1187. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1188. if (!ATALK_SUCCESS(error))
  1189. {
  1190. return error;
  1191. }
  1192. // Build up the user bytes to post the 'SendData' to the remote end.
  1193. userBytes[PAP_CONNECTIONID_OFF] = pPapConn->papco_ConnId;
  1194. userBytes[PAP_CMDTYPE_OFF] = PAP_SEND_DATA;
  1195. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], pPapConn->papco_NextOutgoingSeqNum);
  1196. // PAP Sequence number 0 means unsequenced.
  1197. if (++pPapConn->papco_NextOutgoingSeqNum == 0)
  1198. pPapConn->papco_NextOutgoingSeqNum = 1;
  1199. // Post the SendData request.
  1200. pPapConn->papco_RT.rt_New = AtalkGetCurrentTick();
  1201. if (pPapConn->papco_Flags & PAPCO_SERVER_JOB)
  1202. timeout = pPapConn->papco_RT.rt_Base;
  1203. else timeout = PAP_MAX_SENDDATA_REQ_INTERVAL;
  1204. error = AtalkAtpPostReq(pPapConn->papco_pAtpAddr,
  1205. &pPapConn->papco_RemoteAddr,
  1206. &pPapConn->papco_ReadDataTid,
  1207. ATP_REQ_EXACTLY_ONCE,
  1208. NULL,
  1209. 0,
  1210. userBytes,
  1211. pReadBuf,
  1212. ReadBufLen,
  1213. ATP_INFINITE_RETRIES,
  1214. timeout,
  1215. THIRTY_SEC_TIMER,
  1216. atalkPapIncomingReadComplete,
  1217. pPapConn);
  1218. if (!ATALK_SUCCESS(error))
  1219. {
  1220. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  1221. ("AtalkPapRead: AtalkAtpPostReq %ld\n", error));
  1222. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1223. // Undo the seq number change.
  1224. if (--pPapConn->papco_NextOutgoingSeqNum == 0)
  1225. pPapConn->papco_NextOutgoingSeqNum = (USHORT)0xFFFF;
  1226. pPapConn->papco_Flags &= ~PAPCO_READDATA_PENDING;
  1227. // Clear out read information in the connection object.
  1228. pPapConn->papco_ReadCompletion = NULL;
  1229. pPapConn->papco_ReadCtx = NULL;
  1230. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1231. AtalkPapConnDereference(pPapConn);
  1232. }
  1233. else
  1234. {
  1235. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1236. ("AtalkPapRead: No error - AtalkAtpPostReq tid %lx\n",
  1237. pPapConn->papco_ReadDataTid));
  1238. error = ATALK_PENDING;
  1239. }
  1240. return error;
  1241. }
  1242. ATALK_ERROR
  1243. AtalkPapPrimeRead(
  1244. IN PPAP_CONNOBJ pPapConn,
  1245. IN PACTREQ pActReq
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. Arguments:
  1250. Return Value:
  1251. --*/
  1252. {
  1253. BYTE userBytes[ATP_USERBYTES_SIZE];
  1254. USHORT timeout;
  1255. KIRQL OldIrql;
  1256. ATALK_ERROR error = ATALK_NO_ERROR;
  1257. SHORT MaxRespBufLen;
  1258. ASSERT(VALID_PAPCO(pPapConn));
  1259. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1260. do
  1261. {
  1262. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1263. ("AtalkPapPrimeRead: %lx\n", pPapConn));
  1264. if (pPapConn->papco_Flags & PAPCO_NONBLOCKING_READ)
  1265. {
  1266. error = ATALK_PAP_TOO_MANY_READS;
  1267. break;
  1268. }
  1269. if (pPapConn->papco_Flags & PAPCO_REJECT_READS)
  1270. {
  1271. error = ATALK_PAP_CONN_NOT_ACTIVE;
  1272. break;
  1273. }
  1274. if ((pPapConn->papco_Flags & PAPCO_ACTIVE) == 0)
  1275. {
  1276. error = ATALK_PAP_CONN_NOT_ACTIVE;
  1277. break;
  1278. }
  1279. error = ATALK_INVALID_CONNECTION;
  1280. if ((pPapConn->papco_Flags & (PAPCO_CLOSING |
  1281. PAPCO_STOPPING |
  1282. PAPCO_DELAYED_DISCONNECT |
  1283. PAPCO_DISCONNECTING)) == 0)
  1284. {
  1285. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  1286. }
  1287. if (!ATALK_SUCCESS(error))
  1288. {
  1289. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  1290. ("AtalkPapPrimeRead: Conn %lx Reference Failed %lx\n", pPapConn, error));
  1291. break;
  1292. }
  1293. // Remember info in the connection
  1294. pPapConn->papco_Flags |= PAPCO_NONBLOCKING_READ;
  1295. pPapConn->papco_NbReadLen = 0;
  1296. pPapConn->papco_NbReadActReq = pActReq;
  1297. } while (FALSE);
  1298. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1299. if (!ATALK_SUCCESS(error))
  1300. {
  1301. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1302. ("AtalkPapPrimeRead: Failed %lx.%lx\n", error, pPapConn));
  1303. return error;
  1304. }
  1305. // Build up the user bytes to post the 'SendData' to the remote end.
  1306. userBytes[PAP_CONNECTIONID_OFF] = pPapConn->papco_ConnId;
  1307. userBytes[PAP_CMDTYPE_OFF] = PAP_SEND_DATA;
  1308. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], pPapConn->papco_NextOutgoingSeqNum);
  1309. // PAP Sequence number 0 means unsequenced.
  1310. if (++pPapConn->papco_NextOutgoingSeqNum == 0)
  1311. pPapConn->papco_NextOutgoingSeqNum = 1;
  1312. // Post the SendData request.
  1313. pPapConn->papco_RT.rt_New = AtalkGetCurrentTick();
  1314. if (pPapConn->papco_Flags & PAPCO_SERVER_JOB)
  1315. timeout = pPapConn->papco_RT.rt_Base;
  1316. else timeout = PAP_MAX_SENDDATA_REQ_INTERVAL;
  1317. MaxRespBufLen = (pPapConn->papco_pAtpAddr->atpao_MaxSinglePktSize * ATP_MAX_RESP_PKTS);
  1318. if (pActReq->ar_MdlSize > MaxRespBufLen)
  1319. {
  1320. pActReq->ar_MdlSize = MaxRespBufLen;
  1321. }
  1322. error = AtalkAtpPostReq(pPapConn->papco_pAtpAddr,
  1323. &pPapConn->papco_RemoteAddr,
  1324. &pPapConn->papco_ReadDataTid,
  1325. ATP_REQ_EXACTLY_ONCE, // ExactlyOnce request
  1326. NULL,
  1327. 0,
  1328. userBytes,
  1329. pActReq->ar_pAMdl,
  1330. pActReq->ar_MdlSize,
  1331. ATP_INFINITE_RETRIES,
  1332. timeout,
  1333. THIRTY_SEC_TIMER,
  1334. atalkPapPrimedReadComplete,
  1335. pPapConn);
  1336. if (!ATALK_SUCCESS(error))
  1337. {
  1338. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  1339. ("AtalkPapRead: AtalkAtpPostReq %ld\n", error));
  1340. // Out of resources error log.
  1341. TMPLOGERR();
  1342. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1343. // Undo the seq number change.
  1344. if (--pPapConn->papco_NextOutgoingSeqNum == 0)
  1345. pPapConn->papco_NextOutgoingSeqNum = (USHORT)0xFFFF;
  1346. pPapConn->papco_Flags &= ~PAPCO_NONBLOCKING_READ;
  1347. pPapConn->papco_NbReadActReq = NULL;
  1348. pPapConn->papco_NbReadLen = 0;
  1349. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1350. AtalkPapConnDereference(pPapConn);
  1351. }
  1352. else
  1353. {
  1354. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1355. ("AtalkPapPrimedRead: No error - AtalkAtpPostReq tid %lx\n",
  1356. pPapConn->papco_ReadDataTid));
  1357. error = ATALK_PENDING;
  1358. // If a disconnect happened, cancel prime read just in case disconnect
  1359. // was unable to due to the tid having been uninitialized.
  1360. if (pPapConn->papco_Flags & PAPCO_DISCONNECTING)
  1361. {
  1362. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  1363. ("AtalkPapPrimedRead: DISC When PRIMEREAD %lx.%lx\n",
  1364. pPapConn, pPapConn->papco_Flags));
  1365. AtalkAtpCancelReq(pPapConn->papco_pAtpAddr,
  1366. pPapConn->papco_ReadDataTid,
  1367. &pPapConn->papco_RemoteAddr);
  1368. }
  1369. }
  1370. return error;
  1371. }
  1372. ATALK_ERROR
  1373. AtalkPapWrite(
  1374. IN PPAP_CONNOBJ pPapConn,
  1375. IN PAMDL pWriteBuf,
  1376. IN USHORT WriteBufLen,
  1377. IN ULONG SendFlags,
  1378. IN PVOID pWriteCtx,
  1379. IN GENERIC_WRITE_COMPLETION CompletionRoutine
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. Arguments:
  1384. Return Value:
  1385. --*/
  1386. {
  1387. BOOLEAN sendDataRecd, eom;
  1388. ATALK_ERROR error;
  1389. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  1390. PVOID sendPossibleHandlerCtx;
  1391. KIRQL OldIrql;
  1392. PPAP_ADDROBJ pPapAddr;
  1393. ASSERT(VALID_PAPCO(pPapConn));
  1394. pPapAddr = pPapConn->papco_pAssocAddr;
  1395. ASSERT(VALID_PAPAO(pPapAddr));
  1396. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  1397. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1398. do
  1399. {
  1400. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1401. ("AtalkPapWrite: Buffer size %lx.%lx\n",
  1402. WriteBufLen, pPapConn->papco_SendFlowQuantum * PAP_MAX_DATA_PACKET_SIZE));
  1403. if (WriteBufLen > (pPapConn->papco_SendFlowQuantum * PAP_MAX_DATA_PACKET_SIZE))
  1404. {
  1405. error = ATALK_BUFFER_TOO_BIG;
  1406. ASSERTMSG("AtalkPapWrite: An invalid buffer size used for write\n",
  1407. (WriteBufLen <= (pPapConn->papco_SendFlowQuantum * PAP_MAX_DATA_PACKET_SIZE)));
  1408. break;
  1409. }
  1410. if (pPapConn->papco_Flags & PAPCO_WRITEDATA_WAITING)
  1411. {
  1412. error = ATALK_PAP_TOO_MANY_WRITES;
  1413. ASSERTMSG("AtalkPapWrite: A second write was posted\n", 0);
  1414. break;
  1415. }
  1416. if ((pPapConn->papco_Flags & PAPCO_ACTIVE) == 0)
  1417. {
  1418. error = ATALK_PAP_CONN_NOT_ACTIVE;
  1419. break;
  1420. }
  1421. // Non-blocking sends for PAP:
  1422. // Pap uses a binary event - send data credit thats sent to the remote
  1423. // end. ATP remembers the actual size of the remote entity's response
  1424. // buffer. In any case, if we do not have send credit the call would
  1425. // block, and we dont want that to happen. Also, there should be no
  1426. // pending writes on the connection to begin with.
  1427. //
  1428. if (SendFlags & TDI_SEND_EXPEDITED)
  1429. {
  1430. ASSERTMSG("AtalkPapWrite: Expedited set for pap\n", 0);
  1431. error = ATALK_INVALID_PARAMETER;
  1432. break;
  1433. }
  1434. // This goes away before the call returns. PostSendData has its
  1435. // own reference.
  1436. error = ATALK_INVALID_CONNECTION;
  1437. if ((pPapConn->papco_Flags & ( PAPCO_CLOSING |
  1438. PAPCO_STOPPING |
  1439. PAPCO_DISCONNECTING)) == 0)
  1440. {
  1441. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  1442. if (ATALK_SUCCESS(error))
  1443. {
  1444. sendDataRecd = ((pPapConn->papco_Flags & PAPCO_SENDDATA_RECD) != 0);
  1445. if (!sendDataRecd &&
  1446. (SendFlags & TDI_SEND_NON_BLOCKING))
  1447. {
  1448. // !!!NOTE!!!
  1449. // To avoid the race condition in AFD where an incoming
  1450. // send data indication setting send's possible to true
  1451. // is overwritten by this read's unwinding and setting it
  1452. // to false, we return ATALK_REQUEST_NOT_ACCEPTED, which
  1453. // will map to STATUS_REQUEST_NOT_ACCEPTED and then to
  1454. // WSAEWOULDBLOCK.
  1455. error = ATALK_REQUEST_NOT_ACCEPTED;
  1456. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1457. // We have a reference on the connection we must remove.
  1458. AtalkPapConnDereference(pPapConn);
  1459. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1460. }
  1461. }
  1462. }
  1463. if (!ATALK_SUCCESS(error))
  1464. {
  1465. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1466. ("AtalkPapWrite: Write failed %lx\n", error));
  1467. break;
  1468. }
  1469. error = ATALK_PENDING;
  1470. eom = (SendFlags & TDI_SEND_PARTIAL) ? FALSE : TRUE;
  1471. pPapConn->papco_Flags |= PAPCO_WRITEDATA_WAITING;
  1472. if (eom)
  1473. {
  1474. pPapConn->papco_Flags |= PAPCO_SEND_EOF_WRITE;
  1475. }
  1476. pPapConn->papco_WriteCompletion = CompletionRoutine;
  1477. pPapConn->papco_WriteCtx = pWriteCtx;
  1478. pPapConn->papco_pWriteBuf = pWriteBuf;
  1479. pPapConn->papco_WriteLen = WriteBufLen;
  1480. // Stop further writes from happening by indicating to afd.
  1481. // Call the send data event handler on the associated address with
  1482. // 0 to turn off selects on writes. We do this before we post any
  1483. // get requests, so there is no race condition.
  1484. // remember send possible handler/context.
  1485. sendPossibleHandler = pPapAddr->papao_SendPossibleHandler;
  1486. sendPossibleHandlerCtx = pPapAddr->papao_SendPossibleHandlerCtx;
  1487. } while (FALSE);
  1488. if (ATALK_SUCCESS(error))
  1489. {
  1490. if (sendDataRecd)
  1491. {
  1492. if (*sendPossibleHandler != NULL)
  1493. {
  1494. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  1495. pPapConn->papco_ConnCtx,
  1496. 0);
  1497. }
  1498. // atalkPostSendDataResp() will release the conn lock
  1499. error = atalkPapPostSendDataResp(pPapConn);
  1500. if (!ATALK_SUCCESS(error))
  1501. {
  1502. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1503. pPapConn->papco_Flags &= ~PAPCO_WRITEDATA_WAITING;
  1504. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1505. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  1506. ("AtalkPapWrite: atalkPapPostSendDataResp Failed %lx\n", pPapConn));
  1507. }
  1508. }
  1509. else
  1510. {
  1511. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1512. }
  1513. AtalkPapConnDereference(pPapConn);
  1514. }
  1515. else
  1516. {
  1517. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1518. }
  1519. if (OldIrql != DISPATCH_LEVEL)
  1520. KeLowerIrql(OldIrql);
  1521. return error;
  1522. }
  1523. ATALK_ERROR
  1524. AtalkPapSetStatus(
  1525. IN PPAP_ADDROBJ pPapAddr,
  1526. IN PAMDL pStatusMdl, // NULL if 0-length status
  1527. IN PACTREQ pActReq
  1528. )
  1529. /*++
  1530. Routine Description:
  1531. Arguments:
  1532. Return Value:
  1533. --*/
  1534. {
  1535. NTSTATUS status;
  1536. USHORT stsBufSize=0;
  1537. ULONG bytesCopied;
  1538. KIRQL OldIrql;
  1539. PBYTE pStatusBuf = NULL, pFreeStatusBuf = NULL;
  1540. ASSERT(VALID_PAPAO(pPapAddr));
  1541. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1542. ("AtalkPapSetStatus: Entered for Addr %lx\n", pPapAddr));
  1543. if (pStatusMdl == NULL)
  1544. {
  1545. pStatusBuf = NULL;
  1546. stsBufSize = 0;
  1547. }
  1548. else
  1549. {
  1550. // Allocate a buffer and copy the contents of the passed in
  1551. // buffer descriptor in it. Free an existing status buffer if one exists
  1552. stsBufSize = (USHORT)AtalkSizeMdlChain(pStatusMdl);
  1553. if (stsBufSize >= PAP_MAX_STATUS_SIZE)
  1554. return ATALK_BUFFER_TOO_BIG;
  1555. if (stsBufSize < 0)
  1556. return ATALK_BUFFER_TOO_SMALL;
  1557. }
  1558. if (stsBufSize > 0)
  1559. {
  1560. if ((pStatusBuf = AtalkAllocMemory(stsBufSize)) == NULL)
  1561. {
  1562. return ATALK_RESR_MEM;
  1563. }
  1564. status = TdiCopyMdlToBuffer(pStatusMdl,
  1565. 0,
  1566. pStatusBuf,
  1567. 0,
  1568. stsBufSize,
  1569. &bytesCopied);
  1570. ASSERT(NT_SUCCESS(status) && (bytesCopied == stsBufSize));
  1571. }
  1572. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  1573. pFreeStatusBuf = pPapAddr->papao_pStatusBuf;
  1574. pPapAddr->papao_pStatusBuf = pStatusBuf;
  1575. pPapAddr->papao_StatusSize = stsBufSize;
  1576. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  1577. if (pFreeStatusBuf != NULL)
  1578. {
  1579. AtalkFreeMemory(pFreeStatusBuf);
  1580. }
  1581. // Call the completion routine before returning.
  1582. (*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq);
  1583. return ATALK_NO_ERROR;
  1584. }
  1585. ATALK_ERROR
  1586. AtalkPapGetStatus(
  1587. IN PPAP_ADDROBJ pPapAddr,
  1588. IN PATALK_ADDR pRemoteAddr,
  1589. IN PAMDL pStatusAmdl,
  1590. IN USHORT AmdlSize,
  1591. IN PACTREQ pActReq
  1592. )
  1593. /*++
  1594. Routine Description:
  1595. Arguments:
  1596. The Status Buffer passed in will be preceded by 4 bytes for the
  1597. unused bytes.
  1598. Return Value:
  1599. --*/
  1600. {
  1601. ATALK_ERROR error;
  1602. BYTE userBytes[ATP_USERBYTES_SIZE];
  1603. USHORT tid;
  1604. if ((pRemoteAddr->ata_Network == 0) ||
  1605. (pRemoteAddr->ata_Node == 0) ||
  1606. (pRemoteAddr->ata_Socket == 0))
  1607. {
  1608. return ATALK_SOCKET_INVALID;
  1609. }
  1610. userBytes[PAP_CONNECTIONID_OFF] = 0;
  1611. userBytes[PAP_CMDTYPE_OFF] = PAP_SEND_STATUS;
  1612. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], 0);
  1613. error = AtalkAtpPostReq(pPapAddr->papao_pAtpAddr,
  1614. pRemoteAddr,
  1615. &tid,
  1616. 0, // ExactlyOnce request
  1617. NULL,
  1618. 0,
  1619. userBytes,
  1620. pStatusAmdl,
  1621. AmdlSize,
  1622. PAP_GETSTATUS_REQ_RETRYCOUNT,
  1623. PAP_GETSTATUS_ATP_INTERVAL,
  1624. THIRTY_SEC_TIMER,
  1625. atalkPapIncomingStatus,
  1626. (PVOID)pActReq);
  1627. if (ATALK_SUCCESS(error))
  1628. {
  1629. error = ATALK_PENDING;
  1630. }
  1631. return error;
  1632. }
  1633. VOID
  1634. AtalkPapQuery(
  1635. IN PVOID pObject,
  1636. IN ULONG ObjectType,
  1637. IN PAMDL pAmdl,
  1638. OUT PULONG BytesWritten
  1639. )
  1640. /*++
  1641. Routine Description:
  1642. Arguments:
  1643. Return Value:
  1644. --*/
  1645. {
  1646. switch (ObjectType)
  1647. {
  1648. case TDI_TRANSPORT_ADDRESS_FILE :
  1649. ASSERT(VALID_PAPAO((PPAP_ADDROBJ)pObject));
  1650. AtalkDdpQuery(AtalkPapGetDdpAddress((PPAP_ADDROBJ)pObject),
  1651. pAmdl,
  1652. BytesWritten);
  1653. break;
  1654. case TDI_CONNECTION_FILE :
  1655. {
  1656. PPAP_CONNOBJ pPapConn;
  1657. KIRQL OldIrql;
  1658. pPapConn = (PPAP_CONNOBJ)pObject;
  1659. ASSERT(VALID_PAPCO(pPapConn));
  1660. *BytesWritten = 0;
  1661. // Get the address from the associated address if any.
  1662. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1663. if (pPapConn->papco_Flags & PAPCO_ASSOCIATED)
  1664. {
  1665. AtalkDdpQuery(AtalkPapGetDdpAddress(pPapConn->papco_pAssocAddr),
  1666. pAmdl,
  1667. BytesWritten);
  1668. }
  1669. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1670. }
  1671. break;
  1672. case TDI_CONTROL_CHANNEL_FILE :
  1673. default:
  1674. break;
  1675. }
  1676. }
  1677. LOCAL ATALK_ERROR
  1678. atalkPapRepostConnect(
  1679. IN PPAP_CONNOBJ pPapConn,
  1680. IN PAMDL pOpenAmdl,
  1681. IN PAMDL pRespAmdl
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. Arguments:
  1686. Return Value:
  1687. --*/
  1688. {
  1689. BYTE userBytes[ATP_USERBYTES_SIZE];
  1690. PBYTE pOpenPkt = AtalkGetAddressFromMdlSafe(pOpenAmdl, NormalPagePriority);
  1691. ATALK_ERROR error;
  1692. if (pOpenPkt == NULL) {
  1693. error = ATALK_RESR_MEM;
  1694. return error;
  1695. }
  1696. // Okay, prepare to post the OpenConn request; build up both userBytes and
  1697. // data buffer!
  1698. userBytes[PAP_CONNECTIONID_OFF] = pPapConn->papco_ConnId;
  1699. userBytes[PAP_CMDTYPE_OFF] = PAP_OPEN_CONN;
  1700. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], 0);
  1701. pOpenPkt[PAP_RESP_SOCKET_OFF] = PAPCONN_DDPSOCKET(pPapConn);
  1702. pOpenPkt[PAP_FLOWQUANTUM_OFF] = PAP_MAX_FLOW_QUANTUM;
  1703. PUTDWORD2SHORT(&pOpenPkt[PAP_WAITTIME_OFF], pPapConn->papco_WaitTimeOut);
  1704. // Post the open connection request. We do it on the atp address of the
  1705. // pap address object.
  1706. error = AtalkAtpPostReq(pPapConn->papco_pAtpAddr,
  1707. &pPapConn->papco_RemoteAddr,
  1708. &pPapConn->papco_ConnectTid,
  1709. ATP_REQ_EXACTLY_ONCE, // ExactlyOnce request
  1710. pOpenAmdl,
  1711. PAP_STATUS_OFF,
  1712. userBytes,
  1713. pRespAmdl,
  1714. PAP_MAX_DATA_PACKET_SIZE,
  1715. PAP_OPENCONN_REQ_RETRYCOUNT,
  1716. PAP_OPENCONN_INTERVAL,
  1717. THIRTY_SEC_TIMER,
  1718. atalkPapIncomingOpenReply,
  1719. pPapConn);
  1720. return error;
  1721. }
  1722. LOCAL VOID FASTCALL
  1723. atalkPapAddrDeref(
  1724. IN PPAP_ADDROBJ pPapAddr
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. Arguments:
  1729. Return Value:
  1730. --*/
  1731. {
  1732. KIRQL OldIrql;
  1733. BOOLEAN done = FALSE;
  1734. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  1735. ASSERT(pPapAddr->papao_RefCount > 0);
  1736. if (--pPapAddr->papao_RefCount == 0)
  1737. {
  1738. done = TRUE;
  1739. ASSERT(pPapAddr->papao_Flags & PAPAO_CLOSING);
  1740. }
  1741. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  1742. if (done)
  1743. {
  1744. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1745. ("atalkPapAddrDeref: Addr %lx done with.\n", pPapAddr));
  1746. if (pPapAddr->papao_CloseComp != NULL)
  1747. {
  1748. (*pPapAddr->papao_CloseComp)(ATALK_NO_ERROR,
  1749. pPapAddr->papao_CloseCtx);
  1750. }
  1751. // Remove from the global list.
  1752. ACQUIRE_SPIN_LOCK(&atalkPapLock, &OldIrql);
  1753. AtalkUnlinkDouble(pPapAddr, papao_Next, papao_Prev);
  1754. RELEASE_SPIN_LOCK(&atalkPapLock, OldIrql);
  1755. // Free any status buffer allocated for this address object
  1756. if (pPapAddr->papao_pStatusBuf != NULL)
  1757. AtalkFreeMemory(pPapAddr->papao_pStatusBuf);
  1758. AtalkFreeMemory(pPapAddr);
  1759. AtalkUnlockPapIfNecessary();
  1760. }
  1761. }
  1762. LOCAL VOID FASTCALL
  1763. atalkPapConnRefByPtrNonInterlock(
  1764. IN PPAP_CONNOBJ pPapConn,
  1765. OUT PATALK_ERROR pError
  1766. )
  1767. /*++
  1768. Routine Description:
  1769. Arguments:
  1770. Return Value:
  1771. --*/
  1772. {
  1773. *pError = ATALK_NO_ERROR;
  1774. ASSERT(VALID_PAPCO(pPapConn));
  1775. if ((pPapConn->papco_Flags & PAPCO_CLOSING) == 0)
  1776. {
  1777. ASSERT(pPapConn->papco_RefCount >= 1);
  1778. pPapConn->papco_RefCount ++;
  1779. }
  1780. else
  1781. {
  1782. *pError = ATALK_PAP_CONN_CLOSING;
  1783. }
  1784. }
  1785. LOCAL VOID
  1786. atalkPapConnRefByCtxNonInterlock(
  1787. IN PPAP_ADDROBJ pPapAddr,
  1788. IN CONNECTION_CONTEXT Ctx,
  1789. OUT PPAP_CONNOBJ * pPapConn,
  1790. OUT PATALK_ERROR pError
  1791. )
  1792. /*++
  1793. Routine Description:
  1794. !!!MUST BE CALLED WITH THE ADDRESS SPINLOCK HELD!!!
  1795. Arguments:
  1796. Return Value:
  1797. --*/
  1798. {
  1799. PPAP_CONNOBJ pPapChkConn;
  1800. ATALK_ERROR error = ATALK_PAP_CONN_NOT_FOUND;
  1801. for (pPapChkConn = pPapAddr->papao_pAssocConn;
  1802. pPapChkConn != NULL;
  1803. pPapChkConn = pPapChkConn->papco_pNextAssoc)
  1804. {
  1805. if (pPapChkConn->papco_ConnCtx == Ctx)
  1806. {
  1807. AtalkPapConnReferenceByPtr(pPapChkConn, &error);
  1808. if (ATALK_SUCCESS(error))
  1809. {
  1810. *pPapConn = pPapChkConn;
  1811. }
  1812. break;
  1813. }
  1814. }
  1815. *pError = error;
  1816. }
  1817. LOCAL VOID
  1818. atalkPapConnRefNextNc(
  1819. IN PPAP_CONNOBJ pPapConn,
  1820. IN PPAP_CONNOBJ * ppPapConnNext,
  1821. OUT PATALK_ERROR pError
  1822. )
  1823. /*++
  1824. Routine Description:
  1825. MUST BE CALLED WITH THE ASSOCIATED ADDRESS LOCK HELD!
  1826. Arguments:
  1827. Return Value:
  1828. --*/
  1829. {
  1830. PPAP_CONNOBJ pNextConn = NULL;
  1831. ATALK_ERROR error = ATALK_FAILURE;
  1832. ASSERT(VALID_PAPCO(pPapConn));
  1833. for (; pPapConn != NULL; pPapConn = pPapConn->papco_pNextActive)
  1834. {
  1835. AtalkPapConnReferenceByPtrDpc(pPapConn, &error);
  1836. if (ATALK_SUCCESS(error))
  1837. {
  1838. // Ok, this connection is referenced!
  1839. *ppPapConnNext = pPapConn;
  1840. break;
  1841. }
  1842. }
  1843. *pError = error;
  1844. }
  1845. LOCAL VOID FASTCALL
  1846. atalkPapConnDeref(
  1847. IN PPAP_CONNOBJ pPapConn
  1848. )
  1849. /*++
  1850. Routine Description:
  1851. Disconnect completion happens when the reference count goes from
  1852. 2->1 if the creation reference is not already removed. If the creation
  1853. reference is already removed, it will be done when the refcount goes
  1854. from 1->0.
  1855. Arguments:
  1856. Return Value:
  1857. --*/
  1858. {
  1859. KIRQL OldIrql;
  1860. BOOLEAN fEndProcessing = FALSE;
  1861. ASSERT(VALID_PAPCO(pPapConn));
  1862. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1863. ASSERT(pPapConn->papco_RefCount > 0);
  1864. pPapConn->papco_RefCount--;
  1865. if (pPapConn->papco_RefCount > 1)
  1866. {
  1867. fEndProcessing = TRUE;
  1868. }
  1869. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1870. if (fEndProcessing)
  1871. {
  1872. return;
  1873. }
  1874. else
  1875. {
  1876. PTDI_IND_DISCONNECT discHandler;
  1877. PVOID discCtx;
  1878. ATALK_ERROR disconnectStatus;
  1879. GENERIC_COMPLETION disconnectInform = NULL;
  1880. PVOID disconnectInformCtx = NULL;
  1881. GENERIC_COMPLETION disconnectCompletion = NULL;
  1882. PVOID cleanupCtx = NULL;
  1883. GENERIC_COMPLETION cleanupCompletion = NULL;
  1884. PVOID closeCtx = NULL;
  1885. GENERIC_COMPLETION closeCompletion = NULL;
  1886. PVOID disconnectCtx = NULL;
  1887. PATP_ADDROBJ pAtpAddr = NULL;
  1888. PPAP_ADDROBJ pPapAddr = pPapConn->papco_pAssocAddr;
  1889. BOOLEAN disconnDone = FALSE;
  1890. // We allow stopping phase to happen only after disconnecting is done.
  1891. // If disconnecting is not set and stopping is, it implies we are only
  1892. // in an associated state.
  1893. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1894. if (pPapConn->papco_Flags & PAPCO_DISCONNECTING)
  1895. {
  1896. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1897. ("atalkPapConnDeref: Disconnect set for %lx\n", pPapConn));
  1898. if (pPapConn->papco_RefCount == 1)
  1899. {
  1900. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1901. ("atalkPapConnDeref: Disconnect done %lx\n",
  1902. pPapConn));
  1903. disconnDone = TRUE;
  1904. // Avoid multiple disconnect completions/close atp addresses
  1905. // Remember all the disconnect info before we release the lock
  1906. disconnectInform = pPapConn->papco_DisconnectInform;
  1907. disconnectInformCtx = pPapConn->papco_DisconnectInformCtx;
  1908. disconnectStatus = pPapConn->papco_DisconnectStatus;
  1909. disconnectCompletion = pPapConn->papco_DisconnectCompletion;
  1910. disconnectCtx = pPapConn->papco_DisconnectCtx;
  1911. // The atp address to be closed
  1912. pAtpAddr = pPapConn->papco_pAtpAddr;
  1913. // Reset all the be null, so next request doesnt get any
  1914. pPapConn->papco_DisconnectInform = NULL;
  1915. pPapConn->papco_DisconnectInformCtx = NULL;
  1916. pPapConn->papco_DisconnectCompletion = NULL;
  1917. pPapConn->papco_DisconnectCtx = NULL;
  1918. pPapConn->papco_pAtpAddr = NULL;
  1919. }
  1920. }
  1921. if (pPapConn->papco_RefCount == 0)
  1922. {
  1923. closeCtx = pPapConn->papco_CloseCtx;
  1924. closeCompletion = pPapConn->papco_CloseComp;
  1925. pPapConn->papco_CloseCtx = NULL;
  1926. pPapConn->papco_CloseComp= NULL;
  1927. ASSERT(pPapConn->papco_Flags & PAPCO_CLOSING);
  1928. }
  1929. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  1930. if (disconnDone)
  1931. {
  1932. // Remove from the active queue.
  1933. // Reset all relevent flags.
  1934. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  1935. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1936. atalkPapConnDeQueueActiveList(pPapAddr, pPapConn);
  1937. discHandler = pPapConn->papco_pAssocAddr->papao_DisconnectHandler;
  1938. discCtx = pPapConn->papco_pAssocAddr->papao_DisconnectHandlerCtx;
  1939. // Close the atp address if a server object. If the SERVER_JOB flag
  1940. // is set, it implies that the atp address object was open.
  1941. if ((pPapConn->papco_Flags & PAPCO_SERVER_JOB) == 0)
  1942. {
  1943. pAtpAddr = NULL;
  1944. }
  1945. // This can be done outside the spinlock section. Keep disconnection
  1946. // flag set so no other requests can get in.
  1947. // !!!NOTE!!! We keep the readdata_waiting flag so that the client
  1948. // may read the last set of data sent by the mac.
  1949. pPapConn->papco_Flags &= ~(PAPCO_LISTENING |
  1950. PAPCO_CONNECTING |
  1951. PAPCO_ACTIVE |
  1952. PAPCO_DISCONNECTING |
  1953. PAPCO_READDATA_PENDING |
  1954. PAPCO_WRITEDATA_WAITING |
  1955. PAPCO_NONBLOCKING_READ |
  1956. PAPCO_SENDDATA_RECD);
  1957. pPapConn->papco_Flags |= PAPCO_REJECT_READS;
  1958. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  1959. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  1960. // Call the disconnect completion routines.
  1961. if (*disconnectInform != NULL)
  1962. {
  1963. (*disconnectInform)(disconnectStatus, disconnectInformCtx);
  1964. }
  1965. if (*disconnectCompletion != NULL)
  1966. {
  1967. (*disconnectCompletion)(disconnectStatus, disconnectCtx);
  1968. }
  1969. // Close the atp address if a server object. If the SERVER_JOB flag
  1970. // is set, it implies that the atp address object was open.
  1971. if (pAtpAddr != NULL)
  1972. {
  1973. ASSERT(VALID_ATPAO(pAtpAddr));
  1974. ASSERT(pPapConn->papco_pAtpAddr == NULL);
  1975. AtalkAtpCloseAddress(pAtpAddr, NULL, NULL);
  1976. }
  1977. }
  1978. // Check if we are done with stopping. We could either just be done with
  1979. // disconnect, or be done previously, and just need to complete the stop
  1980. // now.
  1981. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  1982. if ((pPapConn->papco_Flags & PAPCO_STOPPING) != 0)
  1983. {
  1984. BOOLEAN fDisassoc = FALSE;
  1985. // See if we do the cleanup irp completion.
  1986. if (pPapConn->papco_RefCount == 1)
  1987. {
  1988. cleanupCtx = pPapConn->papco_CleanupCtx;
  1989. cleanupCompletion = pPapConn->papco_CleanupComp;
  1990. pPapConn->papco_CleanupComp = NULL;
  1991. pPapConn->papco_CleanupCtx = NULL;
  1992. pPapConn->papco_Flags &= ~PAPCO_STOPPING;
  1993. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  1994. ("atalkPapConnDeref: Cleanup on %lx.%lx\n",
  1995. pPapConn, cleanupCtx));
  1996. }
  1997. if ((pPapConn->papco_Flags & ( PAPCO_LISTENING |
  1998. PAPCO_CONNECTING |
  1999. PAPCO_ACTIVE)) == 0)
  2000. {
  2001. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2002. ("atalkPapConnDeref: Stopping - do disassoc for %lx\n", pPapConn));
  2003. fDisassoc = ((pPapConn->papco_Flags & PAPCO_ASSOCIATED) != 0);
  2004. }
  2005. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2006. // Call the disassociate routine. This should just fail, if the
  2007. // connection is still active or any other state than just
  2008. // plain associated. This will also reset the stopping flag.
  2009. if (fDisassoc)
  2010. {
  2011. AtalkPapDissociateAddress(pPapConn);
  2012. }
  2013. }
  2014. else
  2015. {
  2016. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2017. }
  2018. // Complete cleanup at the end.
  2019. if (*cleanupCompletion != NULL)
  2020. (*cleanupCompletion)(ATALK_NO_ERROR, cleanupCtx);
  2021. if (*closeCompletion != NULL)
  2022. {
  2023. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2024. ("atalkPapConnDeref: Close done for %lx\n", pPapConn));
  2025. // Call the close completion routines
  2026. (*closeCompletion)(ATALK_NO_ERROR, closeCtx);
  2027. // Remove from the global list.
  2028. ACQUIRE_SPIN_LOCK(&atalkPapLock, &OldIrql);
  2029. AtalkUnlinkDouble(pPapConn, papco_Next, papco_Prev);
  2030. RELEASE_SPIN_LOCK(&atalkPapLock, OldIrql);
  2031. // Free up the connection memory.
  2032. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2033. ("atalkPapConnDeref: Freeing up connection %lx\n", pPapConn));
  2034. AtalkUnlockPapIfNecessary();
  2035. AtalkFreeMemory(pPapConn);
  2036. }
  2037. }
  2038. }
  2039. LOCAL ATALK_ERROR FASTCALL
  2040. atalkPapPostSendDataResp(
  2041. IN PPAP_CONNOBJ pPapConn
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. Timing Thoughts: We could get here from PapWrite *only* if we had already
  2046. received a senddata. And so we will not get here from a send data being received
  2047. as it will not be accepted while we have a previous send data pending. The
  2048. other way around- we will only get here from a send data coming in if we
  2049. have a write pending. So we will never get here from write as we would not
  2050. have had a send data pending at that time.
  2051. If the connection reference fails, that means we are shutting down, and
  2052. the shutdown code would already have called the write completion with an
  2053. error. We just get outta here.
  2054. THIS IS CALLED WITH papco_Lock held !!!
  2055. Arguments:
  2056. Return Value:
  2057. --*/
  2058. {
  2059. ATALK_ERROR error;
  2060. PATP_RESP pAtpResp;
  2061. BYTE userBytes[ATP_USERBYTES_SIZE];
  2062. ASSERT(VALID_PAPCO(pPapConn));
  2063. // ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2064. // If we are disconnecting or received a remote disconnect, get out.
  2065. // The disconnect routine would have already cancelled the response.
  2066. error = ATALK_FAILURE;
  2067. if ((pPapConn->papco_Flags & (PAPCO_CLOSING |
  2068. PAPCO_STOPPING |
  2069. PAPCO_DELAYED_DISCONNECT |
  2070. PAPCO_RECVD_DISCONNECT |
  2071. PAPCO_DISCONNECTING)) == 0)
  2072. {
  2073. ASSERT ((pPapConn->papco_Flags & (PAPCO_SENDDATA_RECD | PAPCO_WRITEDATA_WAITING)) ==
  2074. (PAPCO_SENDDATA_RECD | PAPCO_WRITEDATA_WAITING));
  2075. userBytes[PAP_CONNECTIONID_OFF] = pPapConn->papco_ConnId;
  2076. userBytes[PAP_CMDTYPE_OFF] = PAP_DATA;
  2077. // If EOF, need a non-zero value in the first byte.
  2078. PUTSHORT2SHORT(&userBytes[PAP_EOFFLAG_OFF], 0);
  2079. if (pPapConn->papco_Flags & PAPCO_SEND_EOF_WRITE)
  2080. userBytes[PAP_EOFFLAG_OFF] = TRUE;
  2081. pAtpResp = pPapConn->papco_pAtpResp;
  2082. // Reference connection for this send.
  2083. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  2084. if (ATALK_SUCCESS(error))
  2085. {
  2086. AtalkAtpRespReferenceByPtrDpc(pAtpResp, &error);
  2087. }
  2088. else
  2089. {
  2090. // Connection reference failed!
  2091. // Pending write would have been completed by the closing routine.
  2092. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2093. ("AtalkPapPostSendData: Conn ref failed for %lx.%lx\n",
  2094. pPapConn, pPapConn->papco_Flags));
  2095. // This should never happen as we check closing flag above and the reference
  2096. // shouldn't fail for any other reason.
  2097. KeBugCheck(0);
  2098. }
  2099. }
  2100. else
  2101. {
  2102. DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_ERR,
  2103. ("AtalkPapPostSendData: HIT RACE CONDITION conn %lx Resp %lx\n",
  2104. pPapConn, pPapConn->papco_pAtpResp));
  2105. }
  2106. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2107. DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_INFO,
  2108. ("AtalkPapPostSendData: conn %lx Resp %lx\n",
  2109. pPapConn, pPapConn->papco_pAtpResp));
  2110. if (ATALK_SUCCESS(error))
  2111. {
  2112. // Post the response.
  2113. error = AtalkAtpPostResp(pAtpResp,
  2114. &pPapConn->papco_SendDataSrc,
  2115. pPapConn->papco_pWriteBuf,
  2116. pPapConn->papco_WriteLen,
  2117. userBytes,
  2118. atalkPapSendDataRel,
  2119. pPapConn);
  2120. AtalkAtpRespDereference(pAtpResp);
  2121. if (!ATALK_SUCCESS(error))
  2122. {
  2123. // Simulate completion with an error.
  2124. atalkPapSendDataRel(error, pPapConn);
  2125. }
  2126. error = ATALK_PENDING;
  2127. }
  2128. return error;
  2129. }
  2130. LOCAL VOID
  2131. atalkPapIncomingReadComplete(
  2132. IN ATALK_ERROR ErrorCode,
  2133. IN PPAP_CONNOBJ pPapConn, // Our context
  2134. IN PAMDL pReqAmdl,
  2135. IN PAMDL pReadAmdl,
  2136. IN USHORT ReadLen,
  2137. IN PBYTE ReadUserBytes
  2138. )
  2139. /*++
  2140. Routine Description:
  2141. Arguments:
  2142. Return Value:
  2143. --*/
  2144. {
  2145. GENERIC_READ_COMPLETION pReadCompletion;
  2146. PVOID pReadCtx;
  2147. KIRQL OldIrql;
  2148. ULONG readFlags = TDI_RECEIVE_PARTIAL;
  2149. ASSERT(VALID_PAPCO(pPapConn));
  2150. if (ATALK_SUCCESS(ErrorCode))
  2151. {
  2152. // When a read completes, tag that we have heard something from the other side
  2153. pPapConn->papco_LastContactTime = AtalkGetCurrentTick();
  2154. if ((ReadUserBytes[PAP_CONNECTIONID_OFF] != pPapConn->papco_ConnId) ||
  2155. (ReadUserBytes[PAP_CMDTYPE_OFF] != PAP_DATA))
  2156. {
  2157. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2158. ("atalkPapIncomingReadComplete: ReadUserBytes %lx. %lx\n",
  2159. *((PULONG)ReadUserBytes), pPapConn->papco_ConnId));
  2160. ErrorCode = ATALK_PAP_INVALID_USERBYTES;
  2161. }
  2162. if (ReadUserBytes[PAP_EOFFLAG_OFF] != 0)
  2163. {
  2164. readFlags = 0;
  2165. }
  2166. }
  2167. else
  2168. {
  2169. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2170. ("atalkPapIncomingReadComplete: Error %lx for pPapConn %lx\n",
  2171. ErrorCode, pPapConn));
  2172. }
  2173. ASSERT(pReqAmdl == NULL);
  2174. // Estimate the retry interval for next time.
  2175. if (pPapConn->papco_Flags & PAPCO_SERVER_JOB)
  2176. {
  2177. pPapConn->papco_RT.rt_New = AtalkGetCurrentTick() - pPapConn->papco_RT.rt_New;
  2178. AtalkCalculateNewRT(&pPapConn->papco_RT);
  2179. }
  2180. #ifdef PROFILING
  2181. {
  2182. KIRQL OldIrql;
  2183. ACQUIRE_SPIN_LOCK(&AtalkStatsLock, &OldIrql);
  2184. AtalkStatistics.stat_LastPapRTT = (ULONG)(pPapConn->papco_RT.rt_Base);
  2185. if ((ULONG)(pPapConn->papco_RT.rt_Base) > AtalkStatistics.stat_MaxPapRTT)
  2186. AtalkStatistics.stat_MaxPapRTT = (ULONG)(pPapConn->papco_RT.rt_Base);
  2187. RELEASE_SPIN_LOCK(&AtalkStatsLock, OldIrql);
  2188. }
  2189. #endif
  2190. // Before we look at the incoming error code, see if we can mark in the
  2191. // job structure that the other sides sendData is complete.
  2192. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  2193. pPapConn->papco_Flags &= ~PAPCO_READDATA_PENDING;
  2194. pReadCompletion = pPapConn->papco_ReadCompletion;
  2195. pReadCtx = pPapConn->papco_ReadCtx;
  2196. ASSERT(pReadCompletion != NULL);
  2197. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2198. (*pReadCompletion)(ErrorCode, pReadAmdl, ReadLen, readFlags, pReadCtx);
  2199. // Deref the connection object.
  2200. AtalkPapConnDereference(pPapConn);
  2201. }
  2202. LOCAL VOID
  2203. atalkPapPrimedReadComplete(
  2204. IN ATALK_ERROR ErrorCode,
  2205. IN PPAP_CONNOBJ pPapConn, // Our context
  2206. IN PAMDL pReqAmdl,
  2207. IN PAMDL pReadAmdl,
  2208. IN USHORT ReadLen,
  2209. IN PBYTE ReadUserBytes
  2210. )
  2211. /*++
  2212. Routine Description:
  2213. Arguments:
  2214. Return Value:
  2215. --*/
  2216. {
  2217. PTDI_IND_RECEIVE recvHandler;
  2218. PVOID recvHandlerCtx;
  2219. PIRP recvIrp;
  2220. NTSTATUS ntStatus;
  2221. ULONG bytesTaken;
  2222. PBYTE pReadBuf;
  2223. KIRQL OldIrql;
  2224. PACTREQ pActReq;
  2225. BOOLEAN completeRead = FALSE, delayedDisConn = FALSE;
  2226. ULONG readFlags = (TDI_RECEIVE_PARTIAL | TDI_RECEIVE_NORMAL);
  2227. ASSERT(VALID_PAPCO(pPapConn));
  2228. if (ATALK_SUCCESS(ErrorCode))
  2229. {
  2230. if ((ReadUserBytes[PAP_CONNECTIONID_OFF] != pPapConn->papco_ConnId) ||
  2231. (ReadUserBytes[PAP_CMDTYPE_OFF] != PAP_DATA))
  2232. {
  2233. // This will mean a primed read completes with disconnect indication to afd!!
  2234. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2235. ("atalkPapIncomingReadComplete: ReadUserBytes %lx. %lx\n",
  2236. *((PULONG)ReadUserBytes), pPapConn->papco_ConnId));
  2237. ErrorCode = ATALK_PAP_INVALID_USERBYTES;
  2238. }
  2239. if (ReadUserBytes[PAP_EOFFLAG_OFF] != 0)
  2240. {
  2241. readFlags = TDI_RECEIVE_NORMAL;
  2242. }
  2243. }
  2244. else if (ErrorCode == ATALK_ATP_REQ_CANCELLED)
  2245. {
  2246. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2247. ("atalkPapIncomingReadComplete: Request cancelled\n"));
  2248. completeRead = TRUE;
  2249. }
  2250. else
  2251. {
  2252. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2253. ("atalkPapIncomingReadComplete: Error %lx for pPapConn %lx\n",
  2254. ErrorCode, pPapConn));
  2255. }
  2256. ASSERT(pReqAmdl == NULL);
  2257. #ifdef PROFILING
  2258. {
  2259. KIRQL OldIrql;
  2260. ACQUIRE_SPIN_LOCK(&AtalkStatsLock, &OldIrql);
  2261. AtalkStatistics.stat_LastPapRTT = (ULONG)(pPapConn->papco_RT.rt_Base);
  2262. if ((ULONG)(pPapConn->papco_RT.rt_Base) > AtalkStatistics.stat_MaxPapRTT)
  2263. AtalkStatistics.stat_MaxPapRTT = (ULONG)(pPapConn->papco_RT.rt_Base);
  2264. RELEASE_SPIN_LOCK(&AtalkStatsLock, OldIrql);
  2265. }
  2266. #endif
  2267. // Remember the info in the connection object.
  2268. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  2269. pActReq = pPapConn->papco_NbReadActReq;
  2270. recvHandler = pPapConn->papco_pAssocAddr->papao_RecvHandler;
  2271. recvHandlerCtx = pPapConn->papco_pAssocAddr->papao_RecvHandlerCtx;
  2272. if (ATALK_SUCCESS(ErrorCode))
  2273. {
  2274. // When a read completes, tag that we have heard something from the other side
  2275. pPapConn->papco_LastContactTime = AtalkGetCurrentTick();
  2276. // Estimate the retry interval for next time.
  2277. if (pPapConn->papco_Flags & PAPCO_SERVER_JOB)
  2278. {
  2279. pPapConn->papco_RT.rt_New = AtalkGetCurrentTick() - pPapConn->papco_RT.rt_New;
  2280. AtalkCalculateNewRT(&pPapConn->papco_RT);
  2281. }
  2282. pPapConn->papco_Flags |= PAPCO_READDATA_WAITING;
  2283. if (pPapConn->papco_Flags & PAPCO_RECVD_DISCONNECT)
  2284. {
  2285. // AFD gets awfully upset when a read is indicated after a disconnect
  2286. recvHandler = NULL;
  2287. }
  2288. pPapConn->papco_NbReadLen = ReadLen;
  2289. pPapConn->papco_NbReadFlags = readFlags;
  2290. // Get the system address for the mdl
  2291. pReadBuf = (PBYTE)MmGetSystemAddressForMdlSafe(
  2292. pActReq->ar_pAMdl,
  2293. NormalPagePriority);
  2294. if (pReadBuf == NULL)
  2295. {
  2296. pPapConn->papco_Flags &= ~PAPCO_NONBLOCKING_READ;
  2297. pPapConn->papco_NbReadActReq = NULL;
  2298. pPapConn->papco_NbReadLen = 0;
  2299. // Do not indicate a receive
  2300. recvHandler = NULL;
  2301. // Complete the read
  2302. completeRead = TRUE;
  2303. }
  2304. }
  2305. else
  2306. {
  2307. pPapConn->papco_Flags &= ~PAPCO_NONBLOCKING_READ;
  2308. pPapConn->papco_NbReadActReq = NULL;
  2309. pPapConn->papco_NbReadLen = 0;
  2310. pReadBuf = NULL;
  2311. // Do not indicate a receive
  2312. recvHandler = NULL;
  2313. // Complete the read
  2314. completeRead = TRUE;
  2315. }
  2316. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2317. // Call the indication routine on the address object..
  2318. if (*recvHandler != NULL)
  2319. {
  2320. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_WARN,
  2321. ("atalkPapPrimedReadComplete: Indicating when disconnecting!\n"));
  2322. ntStatus = (*recvHandler)(recvHandlerCtx,
  2323. pPapConn->papco_ConnCtx,
  2324. readFlags,
  2325. pPapConn->papco_NbReadLen,
  2326. pPapConn->papco_NbReadLen,
  2327. &bytesTaken,
  2328. pReadBuf,
  2329. &recvIrp);
  2330. ASSERT((bytesTaken == 0) || (bytesTaken == ReadLen));
  2331. if (ntStatus == STATUS_MORE_PROCESSING_REQUIRED)
  2332. {
  2333. if (recvIrp != NULL)
  2334. {
  2335. // Post the receive as if it came from the io system
  2336. ntStatus = AtalkDispatchInternalDeviceControl(
  2337. (PDEVICE_OBJECT)AtalkDeviceObject[ATALK_DEV_PAP],
  2338. recvIrp);
  2339. ASSERT(ntStatus == STATUS_PENDING);
  2340. }
  2341. else
  2342. {
  2343. ASSERTMSG("atalkPapPrimedReadComplete: No receive irp!\n", 0);
  2344. KeBugCheck(0);
  2345. }
  2346. }
  2347. else if (ntStatus == STATUS_SUCCESS)
  2348. {
  2349. // !!!NOTE!!!
  2350. // Its possible that a disconnect happened and completed
  2351. // the pending read already. And so AFD is returning us this
  2352. // for the indication as the connection is already disconnected.
  2353. if (bytesTaken != 0)
  2354. {
  2355. // Assume all of the data was read.
  2356. ASSERT(bytesTaken == ReadLen);
  2357. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2358. ("atalkPapPrimedReadComplete: All bytes read %lx\n",
  2359. bytesTaken));
  2360. // We are done with the primed read.
  2361. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  2362. if (pPapConn->papco_Flags & PAPCO_NONBLOCKING_READ)
  2363. {
  2364. pPapConn->papco_Flags &= ~(PAPCO_NONBLOCKING_READ |
  2365. PAPCO_READDATA_WAITING);
  2366. pPapConn->papco_NbReadActReq = NULL;
  2367. pPapConn->papco_NbReadLen = 0;
  2368. // Complete the read
  2369. completeRead = TRUE;
  2370. }
  2371. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2372. }
  2373. }
  2374. else if (ntStatus == STATUS_DATA_NOT_ACCEPTED)
  2375. {
  2376. // Client may have posted a receive in the indication. Or
  2377. // it will post a receive later on. Do nothing here.
  2378. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2379. ("atalkPapPrimedReadComplete: Indication status %lx\n", ntStatus));
  2380. }
  2381. }
  2382. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  2383. if (pPapConn->papco_Flags & PAPCO_DELAYED_DISCONNECT)
  2384. {
  2385. delayedDisConn = TRUE;
  2386. pPapConn->papco_Flags &= ~PAPCO_DELAYED_DISCONNECT;
  2387. }
  2388. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2389. // Complete the action request.
  2390. if (completeRead)
  2391. {
  2392. // Call the action completion routine for the prime read.
  2393. (*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq);
  2394. }
  2395. // Finally if we have a delayed disconnect, complete the stuff
  2396. if (delayedDisConn)
  2397. {
  2398. AtalkPapDisconnect(pPapConn,
  2399. ATALK_REMOTE_DISCONNECT,
  2400. NULL,
  2401. NULL);
  2402. }
  2403. // Deref the connection object.
  2404. AtalkPapConnDereference(pPapConn);
  2405. }
  2406. LOCAL VOID
  2407. atalkPapIncomingStatus(
  2408. IN ATALK_ERROR ErrorCode,
  2409. IN PACTREQ pActReq, // Our Ctx
  2410. IN PAMDL pReqAmdl,
  2411. IN PAMDL pStatusAmdl,
  2412. IN USHORT StatusLen,
  2413. IN PBYTE ReadUserBytes
  2414. )
  2415. /*++
  2416. Routine Description:
  2417. Arguments:
  2418. Return Value:
  2419. --*/
  2420. {
  2421. // Call the action completion routine
  2422. (*pActReq->ar_Completion)(ErrorCode, pActReq);
  2423. }
  2424. LOCAL VOID FASTCALL
  2425. atalkPapSendDataRel(
  2426. IN ATALK_ERROR ErrorCode,
  2427. IN PPAP_CONNOBJ pPapConn
  2428. )
  2429. /*++
  2430. Routine Description:
  2431. Arguments:
  2432. Return Value:
  2433. --*/
  2434. {
  2435. PAMDL pWriteBuf;
  2436. SHORT writeLen;
  2437. GENERIC_WRITE_COMPLETION writeCompletion;
  2438. PVOID writeCtx;
  2439. PATP_RESP pAtpResp;
  2440. KIRQL OldIrql;
  2441. ASSERT(VALID_PAPCO(pPapConn));
  2442. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2443. ("atalkPapSendDataRel: Error %lx for pPapConn %lx\n", ErrorCode, pPapConn));
  2444. // If this was cancelled, then we turn the error into a no-error.
  2445. if (ErrorCode == ATALK_ATP_RESP_CANCELLED)
  2446. ErrorCode = ATALK_NO_ERROR;
  2447. ACQUIRE_SPIN_LOCK(&pPapConn->papco_Lock, &OldIrql);
  2448. pPapConn->papco_Flags &= ~(PAPCO_WRITEDATA_WAITING |
  2449. PAPCO_SENDDATA_RECD |
  2450. PAPCO_SEND_EOF_WRITE);
  2451. pWriteBuf = pPapConn->papco_pWriteBuf;
  2452. writeLen = pPapConn->papco_WriteLen;
  2453. writeCompletion = pPapConn->papco_WriteCompletion;
  2454. writeCtx = pPapConn->papco_WriteCtx;
  2455. pAtpResp = pPapConn->papco_pAtpResp;
  2456. pPapConn->papco_pAtpResp = NULL;
  2457. ASSERT (pAtpResp != NULL);
  2458. // Reinitialize all the variables.
  2459. pPapConn->papco_WriteLen = 0;
  2460. pPapConn->papco_pWriteBuf = NULL;
  2461. pPapConn->papco_WriteCtx = NULL;
  2462. pPapConn->papco_WriteCompletion = NULL;
  2463. RELEASE_SPIN_LOCK(&pPapConn->papco_Lock, OldIrql);
  2464. (*writeCompletion)(ErrorCode, pWriteBuf, writeLen, writeCtx);
  2465. // Dereference the atp response structure now, but not if a response was never posted
  2466. if (ErrorCode != ATALK_ATP_RESP_CLOSING)
  2467. {
  2468. AtalkAtpRespDereference(pAtpResp);
  2469. }
  2470. else
  2471. {
  2472. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2473. ("atalkPapSendDataRel: Resp cancelled before post %lx\n", pPapConn));
  2474. }
  2475. // Dereference the connection
  2476. AtalkPapConnDereference(pPapConn);
  2477. }
  2478. LOCAL VOID
  2479. atalkPapSlsHandler(
  2480. IN ATALK_ERROR ErrorCode,
  2481. IN PPAP_ADDROBJ pPapAddr, // Listener (our context)
  2482. IN PATP_RESP pAtpResp,
  2483. IN PATALK_ADDR pSrcAddr, // Address of requestor
  2484. IN USHORT PktLen,
  2485. IN PBYTE pPkt,
  2486. IN PBYTE pUserBytes
  2487. )
  2488. /*++
  2489. Routine Description:
  2490. Handler for incoming requests on the Sls. It handles session opens and get
  2491. status on the session.
  2492. Arguments:
  2493. Return Value:
  2494. --*/
  2495. {
  2496. BYTE connId, cmdType;
  2497. BYTE userBytes[ATP_USERBYTES_SIZE];
  2498. PBYTE pRespPkt;
  2499. PAMDL pRespAmdl;
  2500. SHORT respLen;
  2501. PPAP_SEND_STATUS_REL pSendSts;
  2502. BOOLEAN DerefAddr = FALSE;
  2503. ATALK_ERROR error = ATALK_NO_ERROR;
  2504. if (!ATALK_SUCCESS(ErrorCode))
  2505. {
  2506. // Remove the reference on the address object since atp socket is closing
  2507. if (ErrorCode == ATALK_ATP_CLOSING)
  2508. {
  2509. // Remove reference on the connection since socket is closing
  2510. AtalkPapAddrDereference(pPapAddr);
  2511. }
  2512. return;
  2513. }
  2514. // Try to reference the address. If we fail, its probably closing, so
  2515. // get out. This reference will stay around for the duration of this call.
  2516. AtalkPapAddrReference(pPapAddr, &error);
  2517. if (!ATALK_SUCCESS(error))
  2518. {
  2519. if (pAtpResp != NULL)
  2520. {
  2521. AtalkAtpCancelResp(pAtpResp);
  2522. }
  2523. return;
  2524. }
  2525. // If we have a send status request, and we manage to
  2526. // successfully post it, we reset this. And then it goes away in
  2527. // the release routine.
  2528. DerefAddr = TRUE;
  2529. connId = pUserBytes[PAP_CONNECTIONID_OFF];
  2530. cmdType = pUserBytes[PAP_CMDTYPE_OFF];
  2531. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2532. ("atalkPapSlsHandler: Received request %x, tid %x\n",
  2533. cmdType, (pAtpResp != NULL) ? pAtpResp->resp_Tid : 0));
  2534. switch(cmdType)
  2535. {
  2536. case PAP_OPEN_CONN:
  2537. // Ensure packet length is ok.
  2538. // Accept the connection. This will send any error replies as appropriate.
  2539. if ((PktLen < PAP_STATUS_OFF) ||
  2540. !atalkPapConnAccept(pPapAddr,
  2541. pSrcAddr,
  2542. pPkt,
  2543. connId,
  2544. pAtpResp))
  2545. {
  2546. AtalkAtpCancelResp(pAtpResp);
  2547. }
  2548. break;
  2549. case PAP_SEND_STATUS:
  2550. userBytes[PAP_CONNECTIONID_OFF] = 0;
  2551. userBytes[PAP_CMDTYPE_OFF] = PAP_STATUS_REPLY;
  2552. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], 0);
  2553. // We need to put in the status with the spinlock of the
  2554. // address object held.
  2555. ACQUIRE_SPIN_LOCK_DPC(&pPapAddr->papao_Lock);
  2556. do
  2557. {
  2558. // Get a buffer we can send the response with.
  2559. ASSERTMSG("atalkPapSlsHandler: Status size incorrec\n",
  2560. (pPapAddr->papao_StatusSize >= 0));
  2561. if ((pSendSts = AtalkAllocMemory(sizeof(PAP_SEND_STATUS_REL) +
  2562. pPapAddr->papao_StatusSize))== NULL)
  2563. {
  2564. error = ATALK_RESR_MEM;
  2565. break;
  2566. }
  2567. respLen = PAP_STATUS_OFF + 1;
  2568. ASSERT(pPapAddr->papao_StatusSize <= PAP_MAX_STATUS_SIZE);
  2569. pRespPkt = pSendSts->papss_StatusBuf;
  2570. pRespPkt[PAP_STATUS_OFF] = (BYTE)pPapAddr->papao_StatusSize;
  2571. // Zero out the unused portion of the buffer
  2572. PUTDWORD2DWORD(pRespPkt, 0);
  2573. if (pPapAddr->papao_StatusSize > 0)
  2574. {
  2575. RtlCopyMemory(pRespPkt + 1 + PAP_STATUS_OFF,
  2576. pPapAddr->papao_pStatusBuf,
  2577. pPapAddr->papao_StatusSize);
  2578. respLen += pPapAddr->papao_StatusSize;
  2579. ASSERT(respLen <= PAP_MAX_DATA_PACKET_SIZE);
  2580. }
  2581. // Build an mdl for the length that we are using.
  2582. if ((pRespAmdl = AtalkAllocAMdl(pRespPkt, respLen)) == NULL)
  2583. {
  2584. error = ATALK_RESR_MEM;
  2585. AtalkFreeMemory(pSendSts);
  2586. break;
  2587. }
  2588. pSendSts->papss_pAmdl = pRespAmdl;
  2589. pSendSts->papss_pPapAddr = pPapAddr;
  2590. pSendSts->papss_pAtpResp = pAtpResp;
  2591. } while (FALSE);
  2592. RELEASE_SPIN_LOCK_DPC(&pPapAddr->papao_Lock);
  2593. if (!ATALK_SUCCESS(error))
  2594. {
  2595. AtalkAtpCancelResp(pAtpResp);
  2596. break;
  2597. }
  2598. ASSERT(pSendSts != NULL);
  2599. ASSERT((pRespAmdl != NULL) && (respLen > 0));
  2600. error = AtalkAtpPostResp(pAtpResp,
  2601. pSrcAddr,
  2602. pRespAmdl,
  2603. respLen,
  2604. userBytes,
  2605. atalkPapStatusRel,
  2606. pSendSts);
  2607. // atalkPapStatusRel Dereferences the address.
  2608. DerefAddr = FALSE;
  2609. if (!ATALK_SUCCESS(error))
  2610. {
  2611. atalkPapStatusRel(error, pSendSts);
  2612. }
  2613. break;
  2614. default:
  2615. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2616. ("atalkPapSlsHandler: Invalid request %x\n", cmdType));
  2617. AtalkAtpCancelResp(pAtpResp);
  2618. break;
  2619. }
  2620. // Remove reference added at the beginning.
  2621. if (DerefAddr)
  2622. {
  2623. AtalkPapAddrDereference(pPapAddr);
  2624. }
  2625. }
  2626. LOCAL VOID
  2627. atalkPapIncomingReq(
  2628. IN ATALK_ERROR ErrorCode,
  2629. IN PPAP_CONNOBJ pPapConn, // Connection (our context)
  2630. IN PATP_RESP pAtpResp,
  2631. IN PATALK_ADDR pSrcAddr, // Address of requestor
  2632. IN USHORT PktLen,
  2633. IN PBYTE pPkt,
  2634. IN PBYTE pUserBytes
  2635. )
  2636. /*++
  2637. Routine Description:
  2638. This handles requests on a connection, SendData, Tickles, and Close.
  2639. Arguments:
  2640. Return Value:
  2641. --*/
  2642. {
  2643. ATALK_ERROR error;
  2644. BYTE connId, cmdType;
  2645. USHORT seqNum;
  2646. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  2647. PVOID sendPossibleHandlerCtx;
  2648. BOOLEAN DerefConn = FALSE;
  2649. BOOLEAN cancelResp = TRUE;
  2650. ASSERT(VALID_PAPCO(pPapConn));
  2651. do
  2652. {
  2653. if (!ATALK_SUCCESS(ErrorCode))
  2654. {
  2655. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_WARN,
  2656. ("atalkPapIncomingReq: pPapConn %lx, ErrorCode %ld, exit.\n",
  2657. pPapConn, ErrorCode));
  2658. if (ErrorCode == ATALK_ATP_CLOSING)
  2659. {
  2660. // Remove reference on the connection since socket is closing
  2661. AtalkPapConnDereference(pPapConn);
  2662. break;
  2663. }
  2664. }
  2665. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2666. if ((pPapConn->papco_Flags & (PAPCO_ACTIVE |
  2667. PAPCO_STOPPING |
  2668. PAPCO_LOCAL_DISCONNECT|
  2669. PAPCO_DISCONNECTING |
  2670. PAPCO_CLOSING)) == PAPCO_ACTIVE)
  2671. {
  2672. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  2673. }
  2674. else
  2675. {
  2676. error = ATALK_INVALID_CONNECTION;
  2677. }
  2678. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2679. if (!ATALK_SUCCESS(error))
  2680. {
  2681. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2682. ("atalkPapIncomingReq: Ref FAILED/DISC %lx.%lx\n",
  2683. pPapConn, pPapConn->papco_Flags));
  2684. break;
  2685. }
  2686. // Remember to remove connection referenced above
  2687. DerefConn = TRUE;
  2688. connId = pUserBytes[PAP_CONNECTIONID_OFF];
  2689. cmdType = pUserBytes[PAP_CMDTYPE_OFF];
  2690. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2691. ("atalkPapIncomingReq: Received request %x, tid %x\n",
  2692. cmdType, (pAtpResp != NULL) ? pAtpResp->resp_Tid : 0));
  2693. if (connId != pPapConn->papco_ConnId)
  2694. {
  2695. // Just drop this packet. Cancel response though in case this is
  2696. // a xo request
  2697. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2698. ("atalkPapIncomingReq: ConnId %lx recd %lx\n",
  2699. pPapConn->papco_ConnId, connId));
  2700. break;
  2701. }
  2702. pPapConn->papco_LastContactTime = AtalkGetCurrentTick();
  2703. switch (cmdType)
  2704. {
  2705. case PAP_SEND_DATA:
  2706. GETSHORT2SHORT(&seqNum, &pUserBytes[PAP_SEQNUM_OFF]);
  2707. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2708. ("atalkPapIncomingReq: send data %lx recd %lx\n",
  2709. seqNum, pPapConn->papco_ConnId));
  2710. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2711. if ((seqNum == 0) &&
  2712. (pPapConn->papco_Flags & PAPCO_SENDDATA_RECD))
  2713. {
  2714. // We have an unsequenced incoming sendData request before we've
  2715. // finished with the previous one (i.e gotten a release for it).
  2716. // We don't clear the PAPCO_SENDDATA_RECD flag until we receive
  2717. // a release or time out. Also, we cannot assume an implied
  2718. // release as we can with sequenced requests. So we just cancel
  2719. // the response so we can be notified of a retry of the send
  2720. // data request again
  2721. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2722. ("atalkPapIncomingReq: Dropping unseq send data %lx\n", pAtpResp));
  2723. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2724. break;
  2725. }
  2726. if (seqNum != 0)
  2727. {
  2728. // Sequenced send data. Verify the seq num.
  2729. if (seqNum != (USHORT)(pPapConn->papco_NextIncomingSeqNum))
  2730. {
  2731. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2732. ("atalkPapIncomingReq: Out of Seq - current %lx, incoming %lx on %lx\n",
  2733. pPapConn->papco_NextIncomingSeqNum, seqNum, pPapConn));
  2734. // Cancel our response.
  2735. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2736. break;
  2737. }
  2738. if (pPapConn->papco_Flags & PAPCO_SENDDATA_RECD)
  2739. {
  2740. USHORT tid;
  2741. // We have a send data before the previous one has completed.
  2742. // As PAP is a one-request-at-a-time protocol, we can assume
  2743. // that the release for previous transaction is lost. This
  2744. // gets rid of the 30 second pauses when a release is dropped.
  2745. // Cancel our response. Note this implies that a response
  2746. // had been posted by the pap client. In SendRel then, we
  2747. // convert the response cancelled error to no error.
  2748. ASSERT (pPapConn->papco_pAtpResp != NULL);
  2749. tid = pPapConn->papco_pAtpResp->resp_Tid;
  2750. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2751. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_WARN,
  2752. ("atalkPapIncomingReq: Cancelling response tid %x\n", tid));
  2753. // CAUTION: We cannot use AtalkAtpCancelResp() since we have no
  2754. // reference to the resp structure and involves a potential
  2755. // race condition. Play safe and cancel by tid instead.
  2756. error = AtalkAtpCancelRespByTid(pPapConn->papco_pAtpAddr,
  2757. &pPapConn->papco_SendDataSrc,
  2758. tid);
  2759. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2760. ("atalkPapIncomingReq: Cancel error %lx\n", error));
  2761. // If we were unable to cancel the response that means that
  2762. // it already timed out or got a release. We dont want to
  2763. // get into a situation where we would be messing with variables
  2764. // accessed both in the SendDataRel and here. So we just
  2765. // cancel this response and hope to get it again.
  2766. if (!ATALK_SUCCESS(error))
  2767. {
  2768. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_WARN,
  2769. ("atalkPapIncomingReq: Cancel old resp tid %x (%ld)\n",
  2770. tid, error));
  2771. break;
  2772. }
  2773. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2774. pPapConn->papco_pAtpResp = NULL;
  2775. pPapConn->papco_Flags &= ~(PAPCO_SENDDATA_RECD | PAPCO_WRITEDATA_WAITING);
  2776. }
  2777. // Increment the sequence number. If we loop to 0, set to 1.
  2778. if (++pPapConn->papco_NextIncomingSeqNum == 0)
  2779. {
  2780. pPapConn->papco_NextIncomingSeqNum = 1;
  2781. }
  2782. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2783. ("atalkPapIncomingReq: Recd %lx Next %lx\n",
  2784. seqNum, pPapConn->papco_NextIncomingSeqNum));
  2785. }
  2786. else
  2787. {
  2788. // Unsequenced send data received. Handle it.
  2789. ASSERT (seqNum != 0);
  2790. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2791. ("atalkPapIncomingReq: Unsequenced send data recd!\n"));
  2792. }
  2793. cancelResp = FALSE;
  2794. ASSERT((pPapConn->papco_Flags & PAPCO_SENDDATA_RECD) == 0);
  2795. pPapConn->papco_Flags |= PAPCO_SENDDATA_RECD;
  2796. pPapConn->papco_pAtpResp = pAtpResp;
  2797. // The mac may not send its 'SendData' from its responding socket
  2798. // (the one we are tickling and have noted as papco_RemoteAddr), we need
  2799. // to address the response to the socket that the request originated on.
  2800. pPapConn->papco_SendDataSrc = *pSrcAddr;
  2801. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2802. ("atalkPapIncomingReq: send data src %lx.%lx.%lx\n",
  2803. pSrcAddr->ata_Network, pSrcAddr->ata_Node, pSrcAddr->ata_Socket));
  2804. // remember send possible handler/context.
  2805. sendPossibleHandler = pPapConn->papco_pAssocAddr->papao_SendPossibleHandler;
  2806. sendPossibleHandlerCtx = pPapConn->papco_pAssocAddr->papao_SendPossibleHandlerCtx;
  2807. if (pPapConn->papco_Flags & PAPCO_WRITEDATA_WAITING)
  2808. {
  2809. // RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2810. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2811. ("atalkPapIncomingReq: Posting send data resp\n"));
  2812. // atalkPostSendDataResp() will release the conn lock
  2813. atalkPapPostSendDataResp(pPapConn);
  2814. }
  2815. else
  2816. {
  2817. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2818. ("atalkPapIncomingReq: No WriteData waiting\n"));
  2819. if (sendPossibleHandler != NULL)
  2820. {
  2821. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  2822. pPapConn->papco_ConnCtx,
  2823. pPapConn->papco_SendFlowQuantum*PAP_MAX_DATA_PACKET_SIZE);
  2824. }
  2825. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2826. }
  2827. break;
  2828. case PAP_CLOSE_CONN:
  2829. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2830. ("atalkPapIncomingReq: Close conn recvd. for connection %lx\n",
  2831. pPapConn));
  2832. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2833. pPapConn->papco_Flags |= (PAPCO_REMOTE_DISCONNECT | PAPCO_RECVD_DISCONNECT);
  2834. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  2835. // Post the close connection reply.
  2836. cancelResp = FALSE;
  2837. pUserBytes[PAP_CMDTYPE_OFF] = PAP_CLOSE_CONN_REPLY;
  2838. AtalkAtpPostResp(pAtpResp,
  2839. pSrcAddr,
  2840. NULL, // Response buffer
  2841. 0,
  2842. pUserBytes,
  2843. AtalkAtpGenericRespComplete,
  2844. pAtpResp);
  2845. // PapDisconnect will call the disconnect indication routine if set.
  2846. AtalkPapDisconnect(pPapConn,
  2847. ATALK_REMOTE_DISCONNECT,
  2848. NULL,
  2849. NULL);
  2850. break;
  2851. case PAP_TICKLE:
  2852. // We've already registered contact.
  2853. // Cancel this response since we never respond to it and we want this to go away
  2854. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2855. ("atalkPapIncomingReq: Recvd. tickle - resp %lx\n", pAtpResp));
  2856. cancelResp = TRUE;
  2857. break;
  2858. default:
  2859. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2860. ("atalkPapIncomingReq: Invalid command %x\n", cmdType));
  2861. cancelResp = TRUE;
  2862. break;
  2863. }
  2864. } while (FALSE);
  2865. if (cancelResp & (pAtpResp != NULL))
  2866. {
  2867. AtalkAtpCancelResp(pAtpResp);
  2868. }
  2869. if (DerefConn)
  2870. {
  2871. // Remove reference added at the beginning.
  2872. AtalkPapConnDereference(pPapConn);
  2873. }
  2874. }
  2875. LOCAL VOID
  2876. atalkPapIncomingOpenReply(
  2877. IN ATALK_ERROR ErrorCode,
  2878. IN PPAP_CONNOBJ pPapConn, // Our context
  2879. IN PAMDL pReqAmdl,
  2880. IN PAMDL pReadAmdl,
  2881. IN USHORT ReadLen,
  2882. IN PBYTE ReadUserBytes
  2883. )
  2884. /*++
  2885. Routine Description:
  2886. Arguments:
  2887. Return Value:
  2888. --*/
  2889. {
  2890. ULONG index;
  2891. KIRQL OldIrql;
  2892. ATALK_ERROR error;
  2893. USHORT statusLen, i, connectStatus;
  2894. BYTE userBytes[ATP_USERBYTES_SIZE];
  2895. PBYTE pRespPkt, pOpenPkt;
  2896. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  2897. PVOID sendPossibleHandlerCtx;
  2898. PPAP_ADDROBJ pPapAddr = pPapConn->papco_pAssocAddr;
  2899. ASSERT(VALID_PAPCO(pPapConn));
  2900. pRespPkt = pPapConn->papco_pConnectRespBuf;
  2901. pOpenPkt = pPapConn->papco_pConnectOpenBuf;
  2902. ASSERT(pRespPkt != NULL);
  2903. ASSERT(pOpenPkt != NULL);
  2904. if (ATALK_SUCCESS(ErrorCode))
  2905. {
  2906. // Well, lets see what kind of response we got; take a look at both the
  2907. // response user-bytes and the response buffer. Note that we now allow
  2908. // the LaserWriter IIg to leave the status string off altogether,
  2909. // rather than the [correct] zero-sized string.
  2910. do
  2911. {
  2912. // The reply length should be atleast the minimum and it should be
  2913. // an open-reply we are looking at.
  2914. if ((ReadLen < PAP_STATUS_OFF) ||
  2915. (ReadUserBytes[PAP_CMDTYPE_OFF] != PAP_OPEN_CONNREPLY))
  2916. {
  2917. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2918. ("atalkPapIncomingOpenReply: Invalid read len or cmd %x/%x\n",
  2919. ReadLen, ReadUserBytes[PAP_CMDTYPE_OFF]));
  2920. ErrorCode = ATALK_REMOTE_CLOSE;
  2921. break;
  2922. }
  2923. if (ReadLen == PAP_STATUS_OFF)
  2924. {
  2925. statusLen = 0; // Missing, from the LaserWriter IIg
  2926. }
  2927. else
  2928. {
  2929. // Verify length.
  2930. statusLen = pRespPkt[PAP_STATUS_OFF];
  2931. if ((statusLen != 0) &&
  2932. ((statusLen + 1 + PAP_STATUS_OFF) > ReadLen))
  2933. {
  2934. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2935. ("atalkPapIncomingOpenReply: Invalid status len %lx\n", ReadLen));
  2936. ErrorCode = ATALK_REMOTE_CLOSE;
  2937. break;
  2938. }
  2939. }
  2940. // Check for connect result.
  2941. GETSHORT2SHORT(&connectStatus, &pRespPkt[PAP_RESULT_OFF]);
  2942. // Check for open reply code in packet. Do not check the
  2943. // connectionid unless the response is success. Some rips
  2944. // are known to send a bogus connectionid if the return
  2945. // code is 'busy'.
  2946. if ((connectStatus == 0) &&
  2947. (ReadUserBytes[PAP_CONNECTIONID_OFF] != pPapConn->papco_ConnId))
  2948. {
  2949. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  2950. ("atalkPapIncomingOpenReply: Invalid connid %x, expected %x\n",
  2951. ReadUserBytes[PAP_CONNECTIONID_OFF], pPapConn->papco_ConnId));
  2952. ErrorCode = ATALK_REMOTE_CLOSE;
  2953. break;
  2954. }
  2955. if (connectStatus != 0)
  2956. {
  2957. ATALK_ERROR ReconnectError;
  2958. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_WARN,
  2959. ("atalkPapIncomingOpenReply: server busy %lx\n", connectStatus));
  2960. ErrorCode = ATALK_PAP_SERVER_BUSY;
  2961. // If we have not yet reached the max. timeout, retry
  2962. if (pPapConn->papco_WaitTimeOut < PAP_MAX_WAIT_TIMEOUT)
  2963. {
  2964. pPapConn->papco_WaitTimeOut ++;
  2965. ReconnectError = atalkPapRepostConnect(pPapConn, pReqAmdl, pReadAmdl);
  2966. if (ATALK_SUCCESS(ReconnectError))
  2967. return; // Exit now
  2968. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_WARN,
  2969. ("atalkPapIncomingOpenReply: Post reconnect failed %lx\n", ReconnectError));
  2970. }
  2971. break;
  2972. }
  2973. // Switch the socket of the remote address to be the one specified
  2974. // by the remote end.
  2975. pPapConn->papco_RemoteAddr.ata_Socket = pRespPkt[PAP_RESP_SOCKET_OFF];
  2976. pPapConn->papco_SendFlowQuantum = pRespPkt[PAP_FLOWQUANTUM_OFF];
  2977. if (pPapConn->papco_SendFlowQuantum > PAP_MAX_FLOW_QUANTUM)
  2978. {
  2979. pPapConn->papco_SendFlowQuantum = PAP_MAX_FLOW_QUANTUM;
  2980. }
  2981. } while (FALSE);
  2982. if (ATALK_SUCCESS(ErrorCode))
  2983. {
  2984. // Build up userBytes to start tickling the other end.
  2985. userBytes[PAP_CONNECTIONID_OFF] = pPapConn->papco_ConnId;
  2986. userBytes[PAP_CMDTYPE_OFF] = PAP_TICKLE;
  2987. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], 0);
  2988. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  2989. ("atalkPapIncomingOpenReply: id %lx Rem %lx.%lx.%lx RespSkt %lx\n",
  2990. pPapConn->papco_ConnId, pPapConn->papco_RemoteAddr.ata_Network,
  2991. pPapConn->papco_RemoteAddr.ata_Node, pPapConn->papco_RemoteAddr.ata_Socket,
  2992. PAPCONN_DDPSOCKET(pPapConn)));
  2993. error = AtalkAtpPostReq(pPapConn->papco_pAtpAddr,
  2994. &pPapConn->papco_RemoteAddr,
  2995. &pPapConn->papco_TickleTid,
  2996. 0, // ALO transaction
  2997. NULL,
  2998. 0,
  2999. userBytes,
  3000. NULL,
  3001. 0,
  3002. ATP_INFINITE_RETRIES,
  3003. PAP_TICKLE_INTERVAL,
  3004. THIRTY_SEC_TIMER,
  3005. NULL,
  3006. NULL);
  3007. ASSERT(ATALK_SUCCESS(error));
  3008. index = PAP_HASH_ID_ADDR(pPapConn->papco_ConnId, &pPapConn->papco_RemoteAddr);
  3009. // Move the connection from the connect list to the active list.
  3010. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  3011. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3012. // Make sure flags are clean.
  3013. pPapConn->papco_Flags &= ~(PAPCO_SENDDATA_RECD |
  3014. PAPCO_WRITEDATA_WAITING |
  3015. PAPCO_SEND_EOF_WRITE |
  3016. PAPCO_READDATA_PENDING |
  3017. PAPCO_REMOTE_CLOSE |
  3018. PAPCO_NONBLOCKING_READ |
  3019. PAPCO_READDATA_WAITING);
  3020. pPapConn->papco_Flags &= ~PAPCO_CONNECTING;
  3021. pPapConn->papco_Flags |= PAPCO_ACTIVE;
  3022. atalkPapConnDeQueueConnectList(pPapAddr, pPapConn);
  3023. // Thread the connection object into addr lookup by session id.
  3024. pPapConn->papco_pNextActive = pPapAddr->papao_pActiveHash[index];
  3025. pPapAddr->papao_pActiveHash[index] = pPapConn;
  3026. // Reference for the request handler
  3027. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  3028. // Call the send data event handler on the associated address with
  3029. // 0 to turn off selects on writes. We do this before we post any
  3030. // get requests, so there is no race condition.
  3031. // remember send possible handler/context.
  3032. sendPossibleHandler = pPapAddr->papao_SendPossibleHandler;
  3033. sendPossibleHandlerCtx = pPapAddr->papao_SendPossibleHandlerCtx;
  3034. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3035. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  3036. if (sendPossibleHandler != NULL)
  3037. {
  3038. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  3039. pPapConn->papco_ConnCtx,
  3040. 0);
  3041. }
  3042. // Set the request handler on this connection.
  3043. // It will handle tickle's, close's and sendData's.
  3044. AtalkAtpSetReqHandler(pPapConn->papco_pAtpAddr,
  3045. atalkPapIncomingReq,
  3046. pPapConn);
  3047. pPapConn->papco_LastContactTime = AtalkGetCurrentTick();
  3048. }
  3049. else
  3050. {
  3051. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  3052. ("atalkPapIncomingOpenReply: Incoming connect fail %lx\n", ErrorCode));
  3053. // Move the connection out of the connect list.
  3054. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  3055. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3056. pPapConn->papco_Flags &= ~PAPCO_CONNECTING;
  3057. atalkPapConnDeQueueConnectList(pPapAddr, pPapConn);
  3058. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3059. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  3060. }
  3061. }
  3062. else
  3063. {
  3064. // Move the connection out of the connect list.
  3065. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  3066. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3067. atalkPapConnDeQueueConnectList(pPapAddr, pPapConn);
  3068. pPapConn->papco_Flags &= ~PAPCO_CONNECTING;
  3069. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3070. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  3071. }
  3072. // Free the buffers.
  3073. AtalkFreeMemory(pRespPkt);
  3074. AtalkFreeMemory(pOpenPkt);
  3075. AtalkFreeAMdl(pReadAmdl);
  3076. AtalkFreeAMdl(pReqAmdl);
  3077. // Call the completion routine.
  3078. (*pPapConn->papco_ConnectCompletion)(ErrorCode, pPapConn->papco_ConnectCtx);
  3079. // Remove reference for this handler.
  3080. AtalkPapConnDereference(pPapConn);
  3081. }
  3082. LOCAL VOID FASTCALL
  3083. atalkPapIncomingRel(
  3084. IN ATALK_ERROR ErrorCode,
  3085. IN PPAP_OPEN_REPLY_REL pOpenReply
  3086. )
  3087. /*++
  3088. Routine Description:
  3089. Handler for incoming release for reply
  3090. Arguments:
  3091. Return Value:
  3092. --*/
  3093. {
  3094. KIRQL OldIrql;
  3095. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3096. ("atalkPapIncomingRel: Called %lx for pOpenReply %lx\n",
  3097. ErrorCode, pOpenReply));
  3098. ASSERT(pOpenReply != NULL);
  3099. ASSERT(pOpenReply->papor_pRespAmdl != NULL);
  3100. // Dereference the atp response structure now
  3101. AtalkAtpRespDereference(pOpenReply->papor_pAtpResp);
  3102. AtalkFreeAMdl(pOpenReply->papor_pRespAmdl);
  3103. AtalkFreeMemory(pOpenReply);
  3104. }
  3105. LOCAL VOID FASTCALL
  3106. atalkPapStatusRel(
  3107. IN ATALK_ERROR ErrorCode,
  3108. IN PPAP_SEND_STATUS_REL pSendSts
  3109. )
  3110. /*++
  3111. Routine Description:
  3112. Handler for incoming release for reply
  3113. Arguments:
  3114. Return Value:
  3115. --*/
  3116. {
  3117. KIRQL OldIrql;
  3118. UNREFERENCED_PARAMETER(ErrorCode);
  3119. ASSERT(pSendSts != NULL);
  3120. ASSERT(pSendSts->papss_pAmdl != NULL);
  3121. // Dereference the atp response structure now
  3122. AtalkAtpRespDereference(pSendSts->papss_pAtpResp);
  3123. AtalkPapAddrDereference(pSendSts->papss_pPapAddr);
  3124. AtalkFreeAMdl(pSendSts->papss_pAmdl);
  3125. AtalkFreeMemory(pSendSts);
  3126. }
  3127. #define SLS_OPEN_RESP_SOCKET 0x0001
  3128. #define SLS_OPEN_RESP_PKT 0x0002
  3129. #define SLS_OPEN_RESP_MDL 0x0004
  3130. #define SLS_OPEN_CONN_REF 0x0008
  3131. #define SLS_ACCEPT_IRP 0x0010
  3132. #define SLS_CONN_REQ_REFS 0x0020
  3133. #define SLS_CONN_TIMER_REF 0x0040
  3134. #define SLS_LISTEN_DEQUEUED 0x0080
  3135. BOOLEAN
  3136. atalkPapConnAccept(
  3137. IN PPAP_ADDROBJ pPapAddr, // Listener
  3138. IN PATALK_ADDR pSrcAddr, // Address of requestor
  3139. IN PBYTE pPkt,
  3140. IN BYTE ConnId,
  3141. IN PATP_RESP pAtpResp
  3142. )
  3143. /*++
  3144. Routine Description:
  3145. Arguments:
  3146. Return Value:
  3147. --*/
  3148. {
  3149. ATALK_ERROR tmpError;
  3150. BYTE userBytes[ATP_USERBYTES_SIZE];
  3151. PBYTE pRespPkt;
  3152. PAMDL pRespAmdl;
  3153. PATP_ADDROBJ pRespondingAtpAddr;
  3154. PPAP_CONNOBJ pPapConn;
  3155. ULONG index;
  3156. SHORT respLen, i;
  3157. PPAP_OPEN_REPLY_REL pOpenReply;
  3158. GENERIC_COMPLETION listenCompletion;
  3159. PVOID listenCtx;
  3160. KIRQL OldIrql;
  3161. PIRP acceptIrp;
  3162. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  3163. PVOID sendPossibleHandlerCtx;
  3164. USHORT openResr = 0;
  3165. ATALK_ERROR error = ATALK_NO_ERROR;
  3166. BOOLEAN indicate = FALSE;
  3167. BOOLEAN relAddrLock = FALSE;
  3168. BOOLEAN DerefAddr = FALSE;
  3169. BOOLEAN sendOpenErr = FALSE;
  3170. // Get a buffer we can send the response with.
  3171. if ((pOpenReply = (PPAP_OPEN_REPLY_REL)
  3172. AtalkAllocMemory(sizeof(PAP_OPEN_REPLY_REL))) == NULL)
  3173. {
  3174. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  3175. ("atalkPapConnAccept: Could not allocate resp packet\n"));
  3176. return FALSE;
  3177. }
  3178. // NOTE! pOpenReply contains a max sized packet. Get a ptr to work with.
  3179. pRespPkt = pOpenReply->papor_pRespPkt;
  3180. openResr |= SLS_OPEN_RESP_PKT;
  3181. // Build up the response packet. If we encounter an error later on,
  3182. // just set the error code in packet.
  3183. userBytes[PAP_CONNECTIONID_OFF] = ConnId;
  3184. userBytes[PAP_CMDTYPE_OFF] = PAP_OPEN_CONNREPLY;
  3185. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], PAP_NO_ERROR);
  3186. // !!!NOTE!!!
  3187. // The socket will be set after the connection is determined.
  3188. // This will only happen in the non-error case.
  3189. pRespPkt[PAP_FLOWQUANTUM_OFF] = PAP_MAX_FLOW_QUANTUM;
  3190. PUTSHORT2SHORT(&pRespPkt[PAP_RESULT_OFF], 0);
  3191. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  3192. relAddrLock = TRUE;
  3193. do
  3194. {
  3195. // We need to put in the status with the spinlock of the
  3196. // address object held.
  3197. pRespPkt[PAP_STATUS_OFF] = (BYTE)pPapAddr->papao_StatusSize;
  3198. ASSERT((pPapAddr->papao_StatusSize >= 0) &&
  3199. (pPapAddr->papao_StatusSize <= PAP_MAX_STATUS_SIZE));
  3200. if (pPapAddr->papao_StatusSize > 0)
  3201. {
  3202. ASSERT(pPapAddr->papao_pStatusBuf != NULL);
  3203. RtlCopyMemory(pRespPkt+PAP_STATUS_OFF+1,
  3204. pPapAddr->papao_pStatusBuf,
  3205. pPapAddr->papao_StatusSize);
  3206. }
  3207. respLen = PAP_STATUS_OFF + pPapAddr->papao_StatusSize + 1;
  3208. ASSERT(respLen <= PAP_MAX_DATA_PACKET_SIZE);
  3209. // Build an mdl for the length that we are using.
  3210. if ((pRespAmdl = AtalkAllocAMdl(pRespPkt, respLen)) == NULL)
  3211. {
  3212. error = ATALK_RESR_MEM;
  3213. break;
  3214. }
  3215. pOpenReply->papor_pRespAmdl = pRespAmdl;
  3216. pOpenReply->papor_pAtpResp = pAtpResp;
  3217. openResr |= SLS_OPEN_RESP_MDL;
  3218. // Send an open status whatever happens now. If ATALK_SUCCESS(error)
  3219. // we send out a connection accept packets. Assume blocked. If
  3220. // unblocked and we are able to get a connection object, error will
  3221. // be set to success.
  3222. sendOpenErr = TRUE;
  3223. error = ATALK_RESR_MEM;
  3224. // If PapUnblockedState - either there is a GetNextJob posted, or
  3225. // an incoming event handler is set on the listener.
  3226. if (pPapAddr->papao_Flags & PAPAO_UNBLOCKED)
  3227. {
  3228. PTDI_IND_CONNECT indicationRoutine;
  3229. PVOID indicationCtx;
  3230. NTSTATUS status;
  3231. CONNECTION_CONTEXT ConnCtx;
  3232. TA_APPLETALK_ADDRESS tdiAddr;
  3233. // either a getnextjob() or a listener is set.
  3234. // depending on which one it is, dequeue or remember the listener.
  3235. if (pPapAddr->papao_pListenConn != NULL)
  3236. {
  3237. // There a connection with a pending listen. use it.
  3238. pPapConn = pPapAddr->papao_pListenConn;
  3239. if (((pPapAddr->papao_pListenConn = pPapConn->papco_pNextListen) == NULL) &&
  3240. (pPapAddr->papao_ConnHandler == NULL))
  3241. {
  3242. // We have no more listens pending! No event handler either.
  3243. pPapAddr->papao_Flags &= ~PAPAO_UNBLOCKED;
  3244. #if DBG
  3245. pPapAddr->papao_Flags |= PAPAO_BLOCKING;
  3246. #endif
  3247. }
  3248. ASSERT(VALID_PAPCO(pPapConn));
  3249. // Reference the connection object with a listen posted on it.
  3250. AtalkPapConnReferenceByPtrDpc(pPapConn, &error);
  3251. if (!ATALK_SUCCESS(error))
  3252. {
  3253. break;
  3254. }
  3255. // Get the listen completion information
  3256. listenCompletion = pPapConn->papco_ListenCompletion;
  3257. listenCtx = pPapConn->papco_ListenCtx;
  3258. openResr |= (SLS_OPEN_CONN_REF | SLS_LISTEN_DEQUEUED);
  3259. }
  3260. else if ((indicationRoutine = pPapAddr->papao_ConnHandler) != NULL)
  3261. {
  3262. indicationCtx = pPapAddr->papao_ConnHandlerCtx;
  3263. indicate = TRUE;
  3264. // Convert remote atalk address to tdi address
  3265. ATALKADDR_TO_TDI(&tdiAddr, pSrcAddr);
  3266. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  3267. relAddrLock = FALSE;
  3268. acceptIrp = NULL;
  3269. status = (*indicationRoutine)(indicationCtx,
  3270. sizeof(tdiAddr),
  3271. (PVOID)&tdiAddr,
  3272. 0, // User data length
  3273. NULL, // User data
  3274. 0, // Option length
  3275. NULL, // Options
  3276. &ConnCtx,
  3277. &acceptIrp);
  3278. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3279. ("atalkPapConnAccept: indicate status %lx\n", status));
  3280. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  3281. {
  3282. ASSERT(acceptIrp != NULL);
  3283. if (acceptIrp != NULL)
  3284. {
  3285. openResr |= SLS_ACCEPT_IRP;
  3286. }
  3287. // Find the connection and accept the connection using that
  3288. // connection object.
  3289. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  3290. relAddrLock = TRUE;
  3291. AtalkPapConnReferenceByCtxNonInterlock(pPapAddr,
  3292. ConnCtx,
  3293. &pPapConn,
  3294. &error);
  3295. if (!ATALK_SUCCESS(error))
  3296. {
  3297. break;
  3298. }
  3299. openResr |= SLS_OPEN_CONN_REF;
  3300. }
  3301. else
  3302. {
  3303. ASSERT(acceptIrp == NULL);
  3304. error = ATALK_RESR_MEM;
  3305. break;
  3306. }
  3307. }
  3308. else
  3309. {
  3310. // The UNBLOCKED bit was set.
  3311. ASSERT(0);
  3312. KeBugCheck(0);
  3313. }
  3314. }
  3315. if (openResr & SLS_OPEN_CONN_REF)
  3316. {
  3317. if (relAddrLock)
  3318. {
  3319. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  3320. relAddrLock = FALSE;
  3321. }
  3322. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3323. ("atalkPapConnAccept: Creating an Atp address\n"));
  3324. // Now on NT, we will mostly (always) be using the indication, as PAP
  3325. // will be exposed only through winsock.
  3326. error = AtalkAtpOpenAddress(AtalkDefaultPort,
  3327. 0,
  3328. NULL,
  3329. PAP_MAX_DATA_PACKET_SIZE,
  3330. PAP_SEND_USER_BYTES_ALL,
  3331. NULL,
  3332. TRUE, // CACHE address
  3333. &pRespondingAtpAddr);
  3334. if (!ATALK_SUCCESS(error))
  3335. {
  3336. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  3337. ("atalkPapConnAccept: Error open atp resp socket %lx\n", error));
  3338. break;
  3339. }
  3340. openResr |= SLS_OPEN_RESP_SOCKET;
  3341. // Common for both listen and indicate. The connection object
  3342. // should be referenced.
  3343. // Store the information in the connection structure given by
  3344. // the connection object thats passed back in the indication
  3345. // or is part of the getnextjob structure.
  3346. pPapConn->papco_Flags |= PAPCO_SERVER_JOB;
  3347. pPapConn->papco_RemoteAddr = *pSrcAddr;
  3348. pPapConn->papco_RemoteAddr.ata_Socket = pPkt[PAP_RESP_SOCKET_OFF];
  3349. pPapConn->papco_ConnId = ConnId;
  3350. pPapConn->papco_SendFlowQuantum = pPkt[PAP_FLOWQUANTUM_OFF];
  3351. pPapConn->papco_LastContactTime = AtalkGetCurrentTick();
  3352. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3353. ("atalkPapConnAccept: ConnId %lx Rem %lx.%lx.%lx\n",
  3354. ConnId, pSrcAddr->ata_Network, pSrcAddr->ata_Node,
  3355. pPkt[PAP_RESP_SOCKET_OFF]));
  3356. ASSERT(pPapConn->papco_SendFlowQuantum > 0);
  3357. if (pPapConn->papco_SendFlowQuantum > PAP_MAX_FLOW_QUANTUM)
  3358. pPapConn->papco_SendFlowQuantum = PAP_MAX_FLOW_QUANTUM;
  3359. // Thread the connection object into addr lookup by session id.
  3360. index = PAP_HASH_ID_ADDR(ConnId, &pPapConn->papco_RemoteAddr);
  3361. ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
  3362. relAddrLock = TRUE;
  3363. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3364. // Try to reference the connection for the request handler that we
  3365. // are going to set
  3366. AtalkPapConnReferenceByPtrNonInterlock(pPapConn, &error);
  3367. if (!ATALK_SUCCESS(error))
  3368. {
  3369. ASSERT(0);
  3370. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3371. break;
  3372. }
  3373. openResr |= (SLS_CONN_REQ_REFS | SLS_CONN_TIMER_REF);
  3374. // The connection object could be re-used by AFD. Make sure it is
  3375. // in the right state
  3376. pPapConn->papco_NextOutgoingSeqNum = 1; // Set to 1, not 0.
  3377. pPapConn->papco_NextIncomingSeqNum = 1; // Next expected incoming.
  3378. AtalkInitializeRT(&pPapConn->papco_RT,
  3379. PAP_INIT_SENDDATA_REQ_INTERVAL,
  3380. PAP_MIN_SENDDATA_REQ_INTERVAL,
  3381. PAP_MAX_SENDDATA_REQ_INTERVAL);
  3382. pPapConn->papco_Flags &= ~(PAPCO_LISTENING |
  3383. PAPCO_DELAYED_DISCONNECT |
  3384. PAPCO_DISCONNECTING |
  3385. PAPCO_RECVD_DISCONNECT |
  3386. PAPCO_LOCAL_DISCONNECT |
  3387. PAPCO_REMOTE_DISCONNECT |
  3388. PAPCO_SENDDATA_RECD |
  3389. PAPCO_WRITEDATA_WAITING |
  3390. PAPCO_SEND_EOF_WRITE |
  3391. PAPCO_READDATA_PENDING |
  3392. PAPCO_NONBLOCKING_READ |
  3393. PAPCO_READDATA_WAITING |
  3394. #if DBG
  3395. PAPCO_CLEANUP |
  3396. PAPCO_INDICATE_AFD_DISC |
  3397. #endif
  3398. PAPCO_REMOTE_CLOSE);
  3399. pPapConn->papco_Flags |= PAPCO_ACTIVE;
  3400. pPapConn->papco_pNextActive = pPapAddr->papao_pActiveHash[index];
  3401. pPapAddr->papao_pActiveHash[index] = pPapConn;
  3402. // Remember the responding socket.
  3403. pPapConn->papco_pAtpAddr = pRespondingAtpAddr;
  3404. // Set the socket in the packet we'll be sending.
  3405. pRespPkt[PAP_RESP_SOCKET_OFF] = PAPCONN_DDPSOCKET(pPapConn);
  3406. // Call the send data event handler on the associated address with
  3407. // 0 to turn off selects on writes. We do this before we post any
  3408. // get requests, so there is no race condition.
  3409. // remember send possible handler/context.
  3410. sendPossibleHandler = pPapAddr->papao_SendPossibleHandler;
  3411. sendPossibleHandlerCtx = pPapAddr->papao_SendPossibleHandlerCtx;
  3412. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3413. }
  3414. } while (FALSE);
  3415. if (relAddrLock)
  3416. {
  3417. RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
  3418. }
  3419. // This reference needs to go regardless.
  3420. if (openResr & SLS_OPEN_CONN_REF)
  3421. {
  3422. // Remove the reference for the listen dequeued/indication accept.
  3423. AtalkPapConnDereference(pPapConn);
  3424. }
  3425. if (sendOpenErr)
  3426. {
  3427. if (!ATALK_SUCCESS(error))
  3428. {
  3429. // Send error status.
  3430. PUTSHORT2SHORT(&pRespPkt[PAP_RESULT_OFF], PAP_PRINTER_BUSY);
  3431. }
  3432. else
  3433. {
  3434. // Set the request handler on this connection. It will handle
  3435. // tickle's, close's and sendData's. Do this before we send
  3436. // the open reply so that we dont miss the first send data.
  3437. openResr &= ~SLS_CONN_REQ_REFS;
  3438. AtalkAtpSetReqHandler(pPapConn->papco_pAtpAddr,
  3439. atalkPapIncomingReq,
  3440. pPapConn);
  3441. }
  3442. if (ATALK_SUCCESS(AtalkAtpPostResp(pAtpResp,
  3443. pSrcAddr,
  3444. pRespAmdl,
  3445. respLen,
  3446. userBytes,
  3447. atalkPapIncomingRel,
  3448. pOpenReply)))
  3449. {
  3450. // We want the completion to free up the buffer/mdl.
  3451. openResr &= ~(SLS_OPEN_RESP_PKT | SLS_OPEN_RESP_MDL);
  3452. }
  3453. }
  3454. if (ATALK_SUCCESS(error))
  3455. {
  3456. // We better have sent the open reply.
  3457. ASSERT(sendOpenErr);
  3458. ASSERT(VALID_ATPAO(pPapConn->papco_pAtpAddr));
  3459. if ((openResr & (SLS_ACCEPT_IRP & SLS_OPEN_CONN_REF)) ==
  3460. (SLS_ACCEPT_IRP & SLS_OPEN_CONN_REF))
  3461. {
  3462. // Only if we got a referenced connection through an accept
  3463. // do we call the send possible.
  3464. if (sendPossibleHandler != NULL)
  3465. {
  3466. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  3467. pPapConn->papco_ConnCtx,
  3468. 0);
  3469. }
  3470. }
  3471. // Build up userBytes to start tickling the other end.
  3472. userBytes[PAP_CONNECTIONID_OFF] = ConnId;
  3473. userBytes[PAP_CMDTYPE_OFF] = PAP_TICKLE;
  3474. PUTSHORT2SHORT(&userBytes[PAP_SEQNUM_OFF], 0);
  3475. tmpError = AtalkAtpPostReq(pPapConn->papco_pAtpAddr,
  3476. &pPapConn->papco_RemoteAddr,
  3477. &pPapConn->papco_TickleTid,
  3478. 0, // AtLeastOnce
  3479. NULL,
  3480. 0,
  3481. userBytes,
  3482. NULL,
  3483. 0,
  3484. ATP_INFINITE_RETRIES,
  3485. PAP_TICKLE_INTERVAL,
  3486. THIRTY_SEC_TIMER,
  3487. NULL,
  3488. NULL);
  3489. ASSERT(ATALK_SUCCESS(tmpError));
  3490. pPapConn->papco_LastContactTime = AtalkGetCurrentTick();
  3491. }
  3492. else
  3493. {
  3494. // Release all resources
  3495. if (openResr & SLS_OPEN_RESP_SOCKET)
  3496. {
  3497. AtalkAtpCloseAddress(pRespondingAtpAddr, NULL, NULL);
  3498. }
  3499. if (openResr & SLS_OPEN_RESP_MDL)
  3500. {
  3501. AtalkFreeAMdl(pOpenReply->papor_pRespAmdl);
  3502. }
  3503. if (openResr & SLS_OPEN_RESP_PKT)
  3504. {
  3505. AtalkFreeMemory(pOpenReply);
  3506. }
  3507. if (openResr & SLS_CONN_TIMER_REF)
  3508. {
  3509. AtalkPapConnDereference(pPapConn);
  3510. }
  3511. }
  3512. if (openResr & SLS_LISTEN_DEQUEUED)
  3513. {
  3514. ASSERT(!indicate);
  3515. ASSERT(listenCompletion != NULL);
  3516. (*listenCompletion)(error, listenCtx);
  3517. }
  3518. if (openResr & SLS_ACCEPT_IRP)
  3519. {
  3520. acceptIrp->IoStatus.Information = 0;
  3521. ASSERT (error != ATALK_PENDING);
  3522. TdiCompleteRequest(acceptIrp, AtalkErrorToNtStatus(error));
  3523. }
  3524. return sendOpenErr;
  3525. }
  3526. LOCAL LONG FASTCALL
  3527. atalkPapConnMaintenanceTimer(
  3528. IN PTIMERLIST pTimer,
  3529. IN BOOLEAN TimerShuttingDown
  3530. )
  3531. /*++
  3532. Routine Description:
  3533. Arguments:
  3534. Return Value:
  3535. --*/
  3536. {
  3537. PPAP_CONNOBJ pPapConn;
  3538. ATALK_ERROR error;
  3539. BOOLEAN Close;
  3540. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3541. ("atalkPapConnMaintenanceTimer: Entered \n"));
  3542. if (TimerShuttingDown)
  3543. return ATALK_TIMER_NO_REQUEUE;
  3544. ACQUIRE_SPIN_LOCK_DPC(&atalkPapLock);
  3545. // Walk the list of connections on the global list and shut down
  3546. // ones that have not tickle'd for a while
  3547. for (pPapConn = atalkPapConnList; pPapConn != NULL; NOTHING)
  3548. {
  3549. ASSERT(VALID_PAPCO(pPapConn));
  3550. Close = FALSE;
  3551. ACQUIRE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3552. if (((pPapConn->papco_Flags & (PAPCO_ACTIVE |
  3553. PAPCO_CLOSING |
  3554. PAPCO_STOPPING |
  3555. PAPCO_DELAYED_DISCONNECT |
  3556. PAPCO_DISCONNECTING)) == PAPCO_ACTIVE) &&
  3557. ((AtalkGetCurrentTick() - pPapConn->papco_LastContactTime) > PAP_CONNECTION_INTERVAL))
  3558. {
  3559. // Connection has expired.
  3560. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_ERR,
  3561. ("atalkPapConnMaintenanceTimer: Connection %lx.%lx expired\n",
  3562. pPapConn, pPapConn->papco_ConnId));
  3563. Close = TRUE;
  3564. }
  3565. RELEASE_SPIN_LOCK_DPC(&pPapConn->papco_Lock);
  3566. if (Close)
  3567. {
  3568. AtalkPapConnReferenceByPtrDpc(pPapConn, &error);
  3569. if (ATALK_SUCCESS(error))
  3570. {
  3571. RELEASE_SPIN_LOCK_DPC(&atalkPapLock);
  3572. AtalkPapDisconnect(pPapConn,
  3573. ATALK_TIMER_DISCONNECT,
  3574. NULL,
  3575. NULL);
  3576. AtalkPapConnDereference(pPapConn);
  3577. ACQUIRE_SPIN_LOCK_DPC(&atalkPapLock);
  3578. pPapConn = atalkPapConnList;
  3579. }
  3580. }
  3581. if (!Close)
  3582. {
  3583. pPapConn = pPapConn->papco_Next;
  3584. }
  3585. }
  3586. RELEASE_SPIN_LOCK_DPC(&atalkPapLock);
  3587. return ATALK_TIMER_REQUEUE;
  3588. }
  3589. LOCAL BYTE
  3590. atalkPapGetNextConnId(
  3591. IN PPAP_ADDROBJ pPapAddr,
  3592. OUT PATALK_ERROR pError
  3593. )
  3594. /*++
  3595. Routine Description:
  3596. CALLED WITH THE ADDRESS SPIN LOCK HELD!
  3597. Arguments:
  3598. Return Value:
  3599. --*/
  3600. {
  3601. PPAP_CONNOBJ pPapConn;
  3602. USHORT i;
  3603. BYTE startConnId, connId;
  3604. ATALK_ERROR error = ATALK_NO_ERROR;
  3605. startConnId = connId = ++pPapAddr->papao_NextConnId;
  3606. while (TRUE)
  3607. {
  3608. for (i = 0; i < PAP_CONN_HASH_SIZE; i++)
  3609. {
  3610. for (pPapConn = pPapAddr->papao_pActiveHash[i];
  3611. ((pPapConn != NULL) && (pPapConn->papco_ConnId != connId));
  3612. pPapConn = pPapConn->papco_pNextActive)
  3613. NOTHING;
  3614. if (pPapConn != NULL)
  3615. break;
  3616. }
  3617. if (pPapConn == NULL)
  3618. {
  3619. pPapAddr->papao_NextConnId = connId+1;
  3620. break;
  3621. }
  3622. else
  3623. {
  3624. if (connId == (startConnId - 1))
  3625. {
  3626. ASSERT(0);
  3627. // We wrapped around and there are no more conn ids.
  3628. error = ATALK_RESR_MEM;
  3629. break;
  3630. }
  3631. connId++;
  3632. }
  3633. }
  3634. *pError = error;
  3635. return(ATALK_SUCCESS(error) ? connId : 0);
  3636. }
  3637. LOCAL VOID
  3638. atalkPapQueueAddrGlobalList(
  3639. IN PPAP_ADDROBJ pPapAddr
  3640. )
  3641. /*++
  3642. Routine Description:
  3643. Arguments:
  3644. Return Value:
  3645. --*/
  3646. {
  3647. KIRQL OldIrql;
  3648. ACQUIRE_SPIN_LOCK(&atalkPapLock, &OldIrql);
  3649. AtalkLinkDoubleAtHead(atalkPapAddrList, pPapAddr, papao_Next, papao_Prev);
  3650. RELEASE_SPIN_LOCK(&atalkPapLock, OldIrql);
  3651. }
  3652. LOCAL VOID
  3653. atalkPapConnDeQueueAssocList(
  3654. IN PPAP_ADDROBJ pPapAddr,
  3655. IN PPAP_CONNOBJ pPapConn
  3656. )
  3657. /*++
  3658. Routine Description:
  3659. Arguments:
  3660. Return Value:
  3661. --*/
  3662. {
  3663. PPAP_CONNOBJ pPapRemConn, *ppPapRemConn;
  3664. for (ppPapRemConn = &pPapAddr->papao_pAssocConn;
  3665. ((pPapRemConn = *ppPapRemConn) != NULL);
  3666. NOTHING)
  3667. {
  3668. if (pPapRemConn == pPapConn)
  3669. {
  3670. *ppPapRemConn = pPapConn->papco_pNextAssoc;
  3671. break;
  3672. }
  3673. ppPapRemConn = &pPapRemConn->papco_pNextAssoc;
  3674. }
  3675. }
  3676. LOCAL VOID
  3677. atalkPapConnDeQueueConnectList(
  3678. IN PPAP_ADDROBJ pPapAddr,
  3679. IN PPAP_CONNOBJ pPapConn
  3680. )
  3681. /*++
  3682. Routine Description:
  3683. Arguments:
  3684. Return Value:
  3685. --*/
  3686. {
  3687. PPAP_CONNOBJ pPapRemConn, *ppPapRemConn;
  3688. ASSERT(pPapAddr->papao_Flags & PAPAO_CONNECT);
  3689. for (ppPapRemConn = &pPapAddr->papao_pConnectConn;
  3690. ((pPapRemConn = *ppPapRemConn) != NULL);
  3691. NOTHING)
  3692. {
  3693. if (pPapRemConn == pPapConn)
  3694. {
  3695. *ppPapRemConn = pPapConn->papco_pNextConnect;
  3696. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3697. ("atalkPapConnDeQueueConnectList: Removed connect conn %lx\n", pPapConn));
  3698. break;
  3699. }
  3700. ppPapRemConn = &pPapRemConn->papco_pNextConnect;
  3701. }
  3702. }
  3703. LOCAL BOOLEAN
  3704. atalkPapConnDeQueueListenList(
  3705. IN PPAP_ADDROBJ pPapAddr,
  3706. IN PPAP_CONNOBJ pPapConn
  3707. )
  3708. /*++
  3709. Routine Description:
  3710. !!!MUST BE CALLED WITH PAP ADDRESS LOCK HELD!!!
  3711. Arguments:
  3712. Return Value:
  3713. --*/
  3714. {
  3715. PPAP_CONNOBJ pPapRemConn, *ppPapRemConn;
  3716. BOOLEAN removed = FALSE;
  3717. ASSERT(pPapAddr->papao_Flags & PAPAO_LISTENER);
  3718. for (ppPapRemConn = &pPapAddr->papao_pListenConn;
  3719. ((pPapRemConn = *ppPapRemConn) != NULL);
  3720. NOTHING)
  3721. {
  3722. if (pPapRemConn == pPapConn)
  3723. {
  3724. removed = TRUE;
  3725. *ppPapRemConn = pPapConn->papco_pNextListen;
  3726. // If no more listens, then we set the address object to blocked
  3727. // state.
  3728. if ((pPapAddr->papao_pListenConn == NULL) &&
  3729. (pPapAddr->papao_ConnHandler == NULL))
  3730. {
  3731. pPapAddr->papao_Flags &= ~PAPAO_UNBLOCKED;
  3732. #if DBG
  3733. pPapAddr->papao_Flags |= PAPAO_BLOCKING;
  3734. #endif
  3735. }
  3736. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3737. ("atalkPapConnDeQueueListenList: Removed listen conn %lx\n", pPapConn));
  3738. break;
  3739. }
  3740. ppPapRemConn = &pPapRemConn->papco_pNextListen;
  3741. }
  3742. return removed;
  3743. }
  3744. LOCAL VOID
  3745. atalkPapConnDeQueueActiveList(
  3746. IN PPAP_ADDROBJ pPapAddr,
  3747. IN PPAP_CONNOBJ pPapConn
  3748. )
  3749. /*++
  3750. Routine Description:
  3751. Arguments:
  3752. Return Value:
  3753. --*/
  3754. {
  3755. PPAP_CONNOBJ pPapRemConn, *ppPapRemConn;
  3756. ULONG index;
  3757. index = PAP_HASH_ID_ADDR(pPapConn->papco_ConnId, &pPapConn->papco_RemoteAddr);
  3758. for (ppPapRemConn = &pPapAddr->papao_pActiveHash[index];
  3759. ((pPapRemConn = *ppPapRemConn) != NULL);
  3760. NOTHING)
  3761. {
  3762. if (pPapRemConn == pPapConn)
  3763. {
  3764. *ppPapRemConn = pPapConn->papco_pNextActive;
  3765. DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
  3766. ("atalkPapConnDeQueueActiveList: Removed active conn %lx\n", pPapConn));
  3767. break;
  3768. }
  3769. ppPapRemConn = &pPapRemConn->papco_pNextActive;
  3770. }
  3771. }