Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7150 lines
171 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. adsp.c
  5. Abstract:
  6. This module implements the ADSP 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 ADSP
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(INIT, AtalkInitAdspInitialize)
  19. #pragma alloc_text(PAGE, AtalkAdspCreateAddress)
  20. #pragma alloc_text(PAGEADSP, AtalkAdspCreateConnection)
  21. #pragma alloc_text(PAGEADSP, AtalkAdspCleanupAddress)
  22. #pragma alloc_text(PAGEADSP, AtalkAdspCloseAddress)
  23. #pragma alloc_text(PAGEADSP, AtalkAdspCloseConnection)
  24. #pragma alloc_text(PAGEADSP, AtalkAdspCleanupConnection)
  25. #pragma alloc_text(PAGEADSP, AtalkAdspAssociateAddress)
  26. #pragma alloc_text(PAGEADSP, AtalkAdspDissociateAddress)
  27. #pragma alloc_text(PAGEADSP, AtalkAdspPostListen)
  28. #pragma alloc_text(PAGEADSP, AtalkAdspCancelListen)
  29. #pragma alloc_text(PAGEADSP, AtalkAdspPostConnect)
  30. #pragma alloc_text(PAGEADSP, AtalkAdspDisconnect)
  31. #pragma alloc_text(PAGEADSP, AtalkAdspRead)
  32. #pragma alloc_text(PAGEADSP, AtalkAdspProcessQueuedSend)
  33. #pragma alloc_text(PAGEADSP, AtalkAdspWrite)
  34. #pragma alloc_text(PAGEADSP, AtalkAdspQuery)
  35. #pragma alloc_text(PAGEADSP, atalkAdspPacketIn)
  36. #pragma alloc_text(PAGEADSP, atalkAdspHandleOpenControl)
  37. #pragma alloc_text(PAGEADSP, atalkAdspHandleAttn)
  38. #pragma alloc_text(PAGEADSP, atalkAdspHandlePiggyBackAck)
  39. #pragma alloc_text(PAGEADSP, atalkAdspHandleControl)
  40. #pragma alloc_text(PAGEADSP, atalkAdspHandleData)
  41. #pragma alloc_text(PAGEADSP, atalkAdspHandleOpenReq)
  42. #pragma alloc_text(PAGEADSP, atalkAdspListenIndicateNonInterlock)
  43. #pragma alloc_text(PAGEADSP, atalkAdspSendExpedited)
  44. #pragma alloc_text(PAGEADSP, atalkAdspSendOpenControl)
  45. #pragma alloc_text(PAGEADSP, atalkAdspSendControl)
  46. #pragma alloc_text(PAGEADSP, atalkAdspSendDeny)
  47. #pragma alloc_text(PAGEADSP, atalkAdspSendAttn)
  48. #pragma alloc_text(PAGEADSP, atalkAdspSendData)
  49. #pragma alloc_text(PAGEADSP, atalkAdspRecvData)
  50. #pragma alloc_text(PAGEADSP, atalkAdspRecvAttn)
  51. #pragma alloc_text(PAGEADSP, atalkAdspConnSendComplete)
  52. #pragma alloc_text(PAGEADSP, atalkAdspAddrSendComplete)
  53. #pragma alloc_text(PAGEADSP, atalkAdspSendAttnComplete)
  54. #pragma alloc_text(PAGEADSP, atalkAdspSendDataComplete)
  55. #pragma alloc_text(PAGEADSP, atalkAdspConnMaintenanceTimer)
  56. #pragma alloc_text(PAGEADSP, atalkAdspRetransmitTimer)
  57. #pragma alloc_text(PAGEADSP, atalkAdspAttnRetransmitTimer)
  58. #pragma alloc_text(PAGEADSP, atalkAdspOpenTimer)
  59. #pragma alloc_text(PAGEADSP, atalkAdspAddrRefNonInterlock)
  60. #pragma alloc_text(PAGEADSP, atalkAdspConnRefByPtrNonInterlock)
  61. #pragma alloc_text(PAGEADSP, atalkAdspConnRefByCtxNonInterlock)
  62. #pragma alloc_text(PAGEADSP, atalkAdspConnRefBySrcAddr)
  63. #pragma alloc_text(PAGEADSP, atalkAdspConnRefNextNc)
  64. #pragma alloc_text(PAGEADSP, atalkAdspMaxSendSize)
  65. #pragma alloc_text(PAGEADSP, atalkAdspMaxNextReadSize)
  66. #pragma alloc_text(PAGEADSP, atalkAdspDescribeFromBufferQueue)
  67. #pragma alloc_text(PAGEADSP, atalkAdspBufferQueueSize)
  68. #pragma alloc_text(PAGEADSP, atalkAdspMessageSize)
  69. #pragma alloc_text(PAGEADSP, atalkAdspAllocCopyChunk)
  70. #pragma alloc_text(PAGEADSP, atalkAdspGetLookahead)
  71. #pragma alloc_text(PAGEADSP, atalkAdspAddToBufferQueue)
  72. #pragma alloc_text(PAGEADSP, atalkAdspReadFromBufferQueue)
  73. #pragma alloc_text(PAGEADSP, atalkAdspDiscardFromBufferQueue)
  74. #pragma alloc_text(PAGEADSP, atalkAdspBufferChunkReference)
  75. #pragma alloc_text(PAGEADSP, atalkAdspBufferChunkDereference)
  76. #pragma alloc_text(PAGEADSP, atalkAdspDecodeHeader)
  77. #pragma alloc_text(PAGEADSP, atalkAdspGetNextConnId)
  78. #pragma alloc_text(PAGEADSP, atalkAdspConnDeQueueAssocList)
  79. #pragma alloc_text(PAGEADSP, atalkAdspConnDeQueueConnectList)
  80. #pragma alloc_text(PAGEADSP, atalkAdspConnDeQueueListenList)
  81. #pragma alloc_text(PAGEADSP, atalkAdspConnDeQueueActiveList)
  82. #pragma alloc_text(PAGEADSP, atalkAdspAddrDeQueueGlobalList)
  83. #pragma alloc_text(PAGEADSP, atalkAdspAddrDeQueueGlobalList)
  84. #pragma alloc_text(PAGEADSP, atalkAdspConnDeQueueGlobalList)
  85. #pragma alloc_text(PAGEADSP, atalkAdspAddrDeQueueOpenReq)
  86. #pragma alloc_text(PAGEADSP, atalkAdspIsDuplicateOpenReq)
  87. #pragma alloc_text(PAGEADSP, atalkAdspGenericComplete)
  88. #pragma alloc_text(PAGEADSP, atalkAdspConnFindInConnect)
  89. #endif
  90. //
  91. // The model for ADSP calls in this module is as follows:
  92. // - For create calls (CreateAddress & CreateSession), a pointer to the created
  93. // object is returned. This structure is referenced for creation.
  94. // - For all other calls, it expects a referenced pointer to the object.
  95. //
  96. VOID
  97. AtalkInitAdspInitialize(
  98. VOID
  99. )
  100. /*++
  101. Routine Description:
  102. Arguments:
  103. Return Value:
  104. --*/
  105. {
  106. INITIALIZE_SPIN_LOCK(&atalkAdspLock);
  107. }
  108. ATALK_ERROR
  109. AtalkAdspCreateAddress(
  110. IN PATALK_DEV_CTX pDevCtx OPTIONAL,
  111. IN BYTE SocketType,
  112. OUT PADSP_ADDROBJ * ppAdspAddr
  113. )
  114. /*++
  115. Routine Description:
  116. Arguments:
  117. Return Value:
  118. --*/
  119. {
  120. PADSP_ADDROBJ pAdspAddr = NULL;
  121. ATALK_ERROR error;
  122. do
  123. {
  124. // Allocate memory for the Adsp address object
  125. if ((pAdspAddr = AtalkAllocZeroedMemory(sizeof(ADSP_ADDROBJ))) == NULL)
  126. {
  127. error = ATALK_RESR_MEM;
  128. break;
  129. }
  130. // Create a Ddp Socket on the port
  131. error = AtalkDdpOpenAddress(AtalkDefaultPort,
  132. 0, // Dynamic socket
  133. NULL,
  134. atalkAdspPacketIn,
  135. pAdspAddr, // Context for packet in.
  136. DDPPROTO_ADSP,
  137. pDevCtx,
  138. &pAdspAddr->adspao_pDdpAddr);
  139. if (!ATALK_SUCCESS(error))
  140. {
  141. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  142. ("AtalkAdspCreateAddress: AtalkDdpOpenAddress fail %ld\n", error));
  143. break;
  144. }
  145. // Initialize the Adsp address object
  146. pAdspAddr->adspao_Signature = ADSPAO_SIGNATURE;
  147. INITIALIZE_SPIN_LOCK(&pAdspAddr->adspao_Lock);
  148. // Is this a message mode socket?
  149. if (SocketType != SOCKET_TYPE_STREAM)
  150. {
  151. pAdspAddr->adspao_Flags |= ADSPAO_MESSAGE;
  152. }
  153. // Creation reference
  154. pAdspAddr->adspao_RefCount = 1;
  155. } while (FALSE);
  156. if (ATALK_SUCCESS(error))
  157. {
  158. // Insert into the global address list.
  159. atalkAdspAddrQueueGlobalList(pAdspAddr);
  160. *ppAdspAddr = pAdspAddr;
  161. }
  162. else if (pAdspAddr != NULL)
  163. {
  164. AtalkFreeMemory(pAdspAddr);
  165. }
  166. return error;
  167. }
  168. ATALK_ERROR
  169. AtalkAdspCleanupAddress(
  170. IN PADSP_ADDROBJ pAdspAddr
  171. )
  172. /*++
  173. Routine Description:
  174. Arguments:
  175. Return Value:
  176. --*/
  177. {
  178. USHORT i;
  179. KIRQL OldIrql;
  180. PADSP_CONNOBJ pAdspConn, pAdspConnNext;
  181. ATALK_ERROR error;
  182. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  183. // Shutdown all connections on this address object.
  184. for (i = 0; i < ADSP_CONN_HASH_SIZE; i++)
  185. {
  186. if ((pAdspConn = pAdspAddr->adspao_pActiveHash[i]) == NULL)
  187. {
  188. // If empty, go on to the next index in hash table.
  189. continue;
  190. }
  191. // Includes the one we are starting with.
  192. atalkAdspConnRefNextNc(pAdspConn, &pAdspConnNext, &error);
  193. if (!ATALK_SUCCESS(error))
  194. {
  195. // No connections left on this index. Go to the next one.
  196. continue;
  197. }
  198. while (TRUE)
  199. {
  200. if ((pAdspConn = pAdspConnNext) == NULL)
  201. {
  202. break;
  203. }
  204. if ((pAdspConnNext = pAdspConn->adspco_pNextActive) != NULL)
  205. {
  206. atalkAdspConnRefNextNc(pAdspConnNext, &pAdspConnNext, &error);
  207. if (!ATALK_SUCCESS(error))
  208. {
  209. // No requests left on this index. Go to the next one.
  210. pAdspConnNext = NULL;
  211. }
  212. }
  213. // Shutdown this connection
  214. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  215. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  216. ("AtalkAdspCloseAddress: Stopping conn %lx\n", pAdspConn));
  217. AtalkAdspCleanupConnection(pAdspConn);
  218. AtalkAdspConnDereference(pAdspConn);
  219. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  220. }
  221. }
  222. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  223. return ATALK_NO_ERROR;
  224. }
  225. ATALK_ERROR
  226. AtalkAdspCloseAddress(
  227. IN PADSP_ADDROBJ pAdspAddr,
  228. IN GENERIC_COMPLETION CompletionRoutine,
  229. IN PVOID pCloseCtx
  230. )
  231. /*++
  232. Routine Description:
  233. Arguments:
  234. Return Value:
  235. --*/
  236. {
  237. KIRQL OldIrql;
  238. PADSP_CONNOBJ pAdspConn;
  239. PADSP_CONNOBJ pAdspConnNext;
  240. DWORD dwAssocRefCounts=0;
  241. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  242. if (pAdspAddr->adspao_Flags & ADSPAO_CLOSING)
  243. {
  244. // We are already closing! This should never happen!
  245. ASSERT(0);
  246. }
  247. pAdspAddr->adspao_Flags |= ADSPAO_CLOSING;
  248. // Set the completion info.
  249. pAdspAddr->adspao_CloseComp = CompletionRoutine;
  250. pAdspAddr->adspao_CloseCtx = pCloseCtx;
  251. // Implicitly dissociate any connection objects
  252. for (pAdspConn = pAdspAddr->adspao_pAssocConn;
  253. pAdspConn != NULL;
  254. pAdspConn = pAdspConnNext)
  255. {
  256. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  257. pAdspConnNext = pAdspConn->adspco_pNextAssoc;
  258. // reset associated flag
  259. if (pAdspConn->adspco_Flags & ADSPCO_ASSOCIATED)
  260. {
  261. dwAssocRefCounts++;
  262. pAdspConn->adspco_Flags &= ~ADSPCO_ASSOCIATED;
  263. }
  264. pAdspConn->adspco_pAssocAddr = NULL;
  265. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  266. }
  267. // ok to subtract: at least Creation refcount is still around
  268. pAdspAddr->adspao_RefCount -= dwAssocRefCounts;
  269. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  270. // Remove the creation reference count
  271. AtalkAdspAddrDereference(pAdspAddr);
  272. return ATALK_PENDING;
  273. }
  274. ATALK_ERROR
  275. AtalkAdspCreateConnection(
  276. IN PVOID pConnCtx, // Context to associate with the session
  277. IN PATALK_DEV_CTX pDevCtx OPTIONAL,
  278. OUT PADSP_CONNOBJ * ppAdspConn
  279. )
  280. /*++
  281. Routine Description:
  282. Create an ADSP session. The created session starts off being an orphan, i.e.
  283. it has no parent address object. It gets one when it is associated.
  284. Arguments:
  285. Return Value:
  286. --*/
  287. {
  288. KIRQL OldIrql;
  289. PADSP_CONNOBJ pAdspConn;
  290. // Allocate memory for a connection object
  291. if ((pAdspConn = AtalkAllocZeroedMemory(sizeof(ADSP_CONNOBJ))) == NULL)
  292. {
  293. return ATALK_RESR_MEM;
  294. }
  295. pAdspConn->adspco_Signature = ADSPCO_SIGNATURE;
  296. INITIALIZE_SPIN_LOCK(&pAdspConn->adspco_Lock);
  297. pAdspConn->adspco_ConnCtx = pConnCtx;
  298. // pAdspConn->adspco_Flags = 0;
  299. pAdspConn->adspco_RefCount = 1; // Creation reference
  300. *ppAdspConn = pAdspConn;
  301. // Delay remote disconnects to avoid race condn. between rcv/disconnect since
  302. // this can cause AFD to get extremely unhappy.
  303. AtalkTimerInitialize(&pAdspConn->adspco_DisconnectTimer,
  304. atalkAdspDisconnectTimer,
  305. ADSP_DISCONNECT_DELAY);
  306. // Insert into the global connection list.
  307. ACQUIRE_SPIN_LOCK(&atalkAdspLock, &OldIrql);
  308. pAdspConn->adspco_pNextGlobal = atalkAdspConnList;
  309. atalkAdspConnList = pAdspConn;
  310. RELEASE_SPIN_LOCK(&atalkAdspLock, OldIrql);
  311. return ATALK_NO_ERROR;
  312. }
  313. ATALK_ERROR
  314. AtalkAdspCloseConnection(
  315. IN PADSP_CONNOBJ pAdspConn,
  316. IN GENERIC_COMPLETION CompletionRoutine,
  317. IN PVOID pCloseCtx
  318. )
  319. /*++
  320. Routine Description:
  321. Shutdown a session.
  322. Arguments:
  323. Return Value:
  324. --*/
  325. {
  326. KIRQL OldIrql;
  327. ASSERT(VALID_ADSPCO(pAdspConn));
  328. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  329. ("AtalkAdspStopConnection: Close for %lx.%lx\n", pAdspConn, pAdspConn->adspco_Flags));
  330. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  331. if (pAdspConn->adspco_Flags & ADSPCO_CLOSING)
  332. {
  333. // We are already closing! This should never happen!
  334. KeBugCheck(0);
  335. }
  336. pAdspConn->adspco_Flags |= ADSPCO_CLOSING;
  337. // Set the completion info.
  338. pAdspConn->adspco_CloseComp = CompletionRoutine;
  339. pAdspConn->adspco_CloseCtx = pCloseCtx;
  340. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  341. // Remove the creation reference count
  342. AtalkAdspConnDereference(pAdspConn);
  343. return ATALK_PENDING;
  344. }
  345. ATALK_ERROR
  346. AtalkAdspCleanupConnection(
  347. IN PADSP_CONNOBJ pAdspConn
  348. )
  349. /*++
  350. Routine Description:
  351. Shutdown a session.
  352. Arguments:
  353. Return Value:
  354. --*/
  355. {
  356. KIRQL OldIrql;
  357. BOOLEAN stopping = FALSE;
  358. ATALK_ERROR error = ATALK_NO_ERROR;
  359. ASSERT(VALID_ADSPCO(pAdspConn));
  360. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  361. ("AtalkAdspStopConnection: Cleanup for %lx.%lx\n", pAdspConn, pAdspConn->adspco_Flags));
  362. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  363. if ((pAdspConn->adspco_Flags & ADSPCO_STOPPING) == 0)
  364. {
  365. // So Deref can complete cleanup irp.
  366. pAdspConn->adspco_Flags |= ADSPCO_STOPPING;
  367. // If already effectively stopped, just return.
  368. if (pAdspConn->adspco_Flags & ADSPCO_ASSOCIATED)
  369. {
  370. stopping = TRUE;
  371. }
  372. else
  373. {
  374. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  375. ("AtalkAdspStopConnection: Called for a stopped conn %lx.%lx\n",
  376. pAdspConn, pAdspConn->adspco_Flags));
  377. }
  378. }
  379. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  380. // Close the DDP Address Object if this was a server connection and
  381. // opened its own socket.
  382. if (stopping)
  383. {
  384. // If we are already disconnecting this will return an error which
  385. // we ignore. But if we were only in the ASSOCIATED state, then we
  386. // need to call disassociate here.
  387. error = AtalkAdspDisconnect(pAdspConn,
  388. ATALK_LOCAL_DISCONNECT,
  389. NULL,
  390. NULL);
  391. // We were already disconnected.
  392. if (error == ATALK_INVALID_REQUEST)
  393. {
  394. AtalkAdspDissociateAddress(pAdspConn);
  395. }
  396. }
  397. return ATALK_NO_ERROR;
  398. }
  399. ATALK_ERROR
  400. AtalkAdspAssociateAddress(
  401. IN PADSP_ADDROBJ pAdspAddr,
  402. IN PADSP_CONNOBJ pAdspConn
  403. )
  404. /*++
  405. Routine Description:
  406. Removed reference for the address for this connection. Causes deadlock in AFD where
  407. AFD blocks on close of the address object and we wait for connections to be closed
  408. first
  409. Arguments:
  410. Return Value:
  411. --*/
  412. {
  413. ATALK_ERROR error;
  414. KIRQL OldIrql;
  415. ASSERT(VALID_ADSPAO(pAdspAddr));
  416. ASSERT(VALID_ADSPCO(pAdspConn));
  417. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  418. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  419. error = ATALK_ALREADY_ASSOCIATED;
  420. if ((pAdspConn->adspco_Flags & ADSPCO_ASSOCIATED) == 0)
  421. {
  422. error = ATALK_NO_ERROR;
  423. // Link it in.
  424. pAdspConn->adspco_pNextAssoc = pAdspAddr->adspao_pAssocConn;
  425. pAdspAddr->adspao_pAssocConn = pAdspConn;
  426. // Remove not associated flag.
  427. pAdspConn->adspco_Flags |= ADSPCO_ASSOCIATED;
  428. pAdspConn->adspco_pAssocAddr = pAdspAddr;
  429. // put Association refcount
  430. pAdspAddr->adspao_RefCount++;
  431. }
  432. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  433. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  434. return error;
  435. }
  436. ATALK_ERROR
  437. AtalkAdspDissociateAddress(
  438. IN PADSP_CONNOBJ pAdspConn
  439. )
  440. /*++
  441. Routine Description:
  442. Arguments:
  443. Return Value:
  444. --*/
  445. {
  446. PADSP_ADDROBJ pAdspAddr;
  447. KIRQL OldIrql;
  448. ATALK_ERROR error = ATALK_NO_ERROR;
  449. ASSERT(VALID_ADSPCO(pAdspConn));
  450. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  451. if ((pAdspConn->adspco_Flags & (ADSPCO_LISTENING |
  452. ADSPCO_CONNECTING |
  453. ADSPCO_ACTIVE |
  454. ADSPCO_ASSOCIATED)) != ADSPCO_ASSOCIATED)
  455. {
  456. // ASSERTMSG("AtalkAdspDissociateAddress: Disassociate not valid\n", 0);
  457. error = ATALK_INVALID_CONNECTION;
  458. }
  459. else
  460. {
  461. pAdspAddr = pAdspConn->adspco_pAssocAddr ;
  462. if (pAdspAddr == NULL)
  463. {
  464. ASSERT(0);
  465. error = ATALK_CANNOT_DISSOCIATE;
  466. }
  467. // Set not associated flag. Don't reset the stopping flag.
  468. pAdspConn->adspco_Flags &= ~ADSPCO_ASSOCIATED;
  469. // don't null it out yet: we'll do when we disconnect the connection
  470. // pAdspConn->adspco_pAssocAddr = NULL;
  471. }
  472. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  473. // Unlink it if ok.
  474. if (ATALK_SUCCESS(error))
  475. {
  476. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  477. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  478. atalkAdspConnDeQueueAssocList(pAdspAddr, pAdspConn);
  479. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  480. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  481. // remove the Association refcount
  482. AtalkAdspAddrDereference(pAdspAddr);
  483. }
  484. return error;
  485. }
  486. ATALK_ERROR
  487. AtalkAdspPostListen(
  488. IN PADSP_CONNOBJ pAdspConn,
  489. IN PVOID pListenCtx,
  490. IN GENERIC_COMPLETION CompletionRoutine
  491. )
  492. /*++
  493. Routine Description:
  494. Arguments:
  495. Return Value:
  496. --*/
  497. {
  498. PADSP_ADDROBJ pAdspAddr = pAdspConn->adspco_pAssocAddr;
  499. KIRQL OldIrql;
  500. ATALK_ERROR error;
  501. // This will also insert the connection object in the address objects
  502. // list of connection which have a listen posted on them. When open
  503. // connection requests come in, the first connection is taken off the list
  504. // and the request satisfied.
  505. ASSERT(VALID_ADSPCO(pAdspConn));
  506. ASSERT(VALID_ADSPAO(pAdspAddr));
  507. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  508. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  509. do
  510. {
  511. if ((pAdspConn->adspco_Flags & (ADSPCO_LISTENING |
  512. ADSPCO_CONNECTING |
  513. ADSPCO_HALF_ACTIVE |
  514. ADSPCO_ACTIVE |
  515. ADSPCO_ASSOCIATED)) != ADSPCO_ASSOCIATED)
  516. {
  517. error = ATALK_INVALID_CONNECTION;
  518. break;
  519. }
  520. // Verify the address object is not a connect address type.
  521. if (pAdspAddr->adspao_Flags & ADSPAO_CONNECT)
  522. {
  523. error = ATALK_INVALID_PARAMETER;
  524. break;
  525. }
  526. // Make the address object a listener.
  527. pAdspAddr->adspao_Flags |= ADSPAO_LISTENER;
  528. pAdspConn->adspco_Flags |= ADSPCO_LISTENING;
  529. pAdspConn->adspco_ListenCtx = pListenCtx;
  530. pAdspConn->adspco_ListenCompletion = CompletionRoutine;
  531. // Insert into the listen list.
  532. pAdspConn->adspco_pNextListen = pAdspAddr->adspao_pListenConn;
  533. pAdspAddr->adspao_pListenConn = pAdspConn;
  534. // Inherits the address objects ddp address
  535. pAdspConn->adspco_pDdpAddr = pAdspAddr->adspao_pDdpAddr;
  536. // Initialize pended sends list
  537. InitializeListHead(&pAdspConn->adspco_PendedSends);
  538. error = ATALK_PENDING;
  539. } while (FALSE);
  540. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  541. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  542. return error;
  543. }
  544. ATALK_ERROR
  545. AtalkAdspCancelListen(
  546. IN PADSP_CONNOBJ pAdspConn
  547. )
  548. /*++
  549. Routine Description:
  550. Cancel a previously posted listen.
  551. Arguments:
  552. Return Value:
  553. --*/
  554. {
  555. PADSP_ADDROBJ pAdspAddr = pAdspConn->adspco_pAssocAddr;
  556. KIRQL OldIrql;
  557. ATALK_ERROR error = ATALK_NO_ERROR;
  558. GENERIC_COMPLETION completionRoutine = NULL;
  559. PVOID completionCtx = NULL;
  560. ASSERT(VALID_ADSPCO(pAdspConn));
  561. ASSERT(VALID_ADSPAO(pAdspAddr));
  562. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  563. if (!atalkAdspConnDeQueueListenList(pAdspAddr, pAdspConn))
  564. {
  565. error = ATALK_INVALID_CONNECTION;
  566. }
  567. else
  568. {
  569. // We complete the listen routine
  570. ASSERT(pAdspConn->adspco_Flags & ADSPCO_LISTENING);
  571. pAdspConn->adspco_Flags &= ~ADSPCO_LISTENING;
  572. completionRoutine = pAdspConn->adspco_ListenCompletion;
  573. completionCtx = pAdspConn->adspco_ListenCtx;
  574. }
  575. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  576. if (*completionRoutine != NULL)
  577. {
  578. (*completionRoutine)(ATALK_REQUEST_CANCELLED, completionCtx);
  579. }
  580. return error;
  581. }
  582. ATALK_ERROR
  583. AtalkAdspPostConnect(
  584. IN PADSP_CONNOBJ pAdspConn,
  585. IN PATALK_ADDR pRemote_Addr,
  586. IN PVOID pConnectCtx,
  587. IN GENERIC_COMPLETION CompletionRoutine
  588. )
  589. /*++
  590. Routine Description:
  591. Arguments:
  592. Return Value:
  593. --*/
  594. {
  595. ATALK_ERROR error;
  596. KIRQL OldIrql;
  597. BOOLEAN DerefConn = FALSE;
  598. PADSP_ADDROBJ pAdspAddr = pAdspConn->adspco_pAssocAddr;
  599. ASSERT(VALID_ADSPCO(pAdspConn));
  600. ASSERT(VALID_ADSPAO(pAdspAddr));
  601. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  602. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  603. do
  604. {
  605. if ((pAdspConn->adspco_Flags & (ADSPCO_LISTENING |
  606. ADSPCO_CONNECTING |
  607. ADSPCO_HALF_ACTIVE |
  608. ADSPCO_ACTIVE |
  609. ADSPCO_ASSOCIATED)) != ADSPCO_ASSOCIATED)
  610. {
  611. error = ATALK_INVALID_CONNECTION;
  612. break;
  613. }
  614. // Verify the address object is not a listener address type.
  615. if (pAdspAddr->adspao_Flags & ADSPAO_LISTENER)
  616. {
  617. error = ATALK_INVALID_ADDRESS;
  618. break;
  619. }
  620. // Reference the connection for this call and for the timer.
  621. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 2, &error);
  622. if (!ATALK_SUCCESS(error))
  623. {
  624. ASSERTMSG("AtalkAdspPostConnect: Connection ref failed\n", 0);
  625. break;
  626. }
  627. DerefConn = TRUE;
  628. pAdspConn->adspco_LocalConnId = atalkAdspGetNextConnId(pAdspAddr,
  629. &error);
  630. if (ATALK_SUCCESS(error))
  631. {
  632. pAdspConn->adspco_Flags |= (ADSPCO_CONNECTING | ADSPCO_OPEN_TIMER);
  633. pAdspConn->adspco_ConnectCtx = pConnectCtx;
  634. pAdspConn->adspco_ConnectCompletion = CompletionRoutine;
  635. pAdspConn->adspco_RemoteAddr = *pRemote_Addr;
  636. pAdspConn->adspco_ConnectAttempts = ADSP_MAX_OPEN_ATTEMPTS;
  637. // Insert into the connect list.
  638. pAdspConn->adspco_pNextConnect = pAdspAddr->adspao_pConnectConn;
  639. pAdspAddr->adspao_pConnectConn = pAdspConn;
  640. pAdspAddr->adspao_Flags |= ADSPAO_CONNECT;
  641. pAdspConn->adspco_RecvWindow=
  642. pAdspConn->adspco_SendQueueMax =
  643. pAdspConn->adspco_RecvQueueMax = ADSP_DEF_SEND_RX_WINDOW_SIZE;
  644. // Inherits the address objects ddp address
  645. pAdspConn->adspco_pDdpAddr = pAdspAddr->adspao_pDdpAddr;
  646. // Initialize pended sends list
  647. InitializeListHead(&pAdspConn->adspco_PendedSends);
  648. // Start the open timer
  649. AtalkTimerInitialize(&pAdspConn->adspco_OpenTimer,
  650. atalkAdspOpenTimer,
  651. ADSP_OPEN_INTERVAL);
  652. AtalkTimerScheduleEvent(&pAdspConn->adspco_OpenTimer);
  653. }
  654. else
  655. {
  656. ASSERTMSG("AtalkAdspPostConnect: Unable to get conn id\n", 0);
  657. error = ATALK_RESR_MEM;
  658. RES_LOG_ERROR();
  659. break;
  660. }
  661. } while (FALSE);
  662. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  663. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  664. if (ATALK_SUCCESS(error))
  665. {
  666. // Send connect packet to the remote end. This will add its
  667. // own references.
  668. atalkAdspSendOpenControl(pAdspConn);
  669. error = ATALK_PENDING;
  670. }
  671. else
  672. {
  673. if (DerefConn)
  674. {
  675. // Remove the reference for timer only if error.
  676. AtalkAdspConnDereference(pAdspConn);
  677. }
  678. }
  679. if (DerefConn)
  680. {
  681. // Remove the reference for call
  682. AtalkAdspConnDereference(pAdspConn);
  683. }
  684. return error;
  685. }
  686. #define atalkAdspCompleteQueuedSends(_pAdspConn, _error) \
  687. { \
  688. ULONG writeBufLen; \
  689. PVOID writeCtx; \
  690. \
  691. while (!IsListEmpty(&(_pAdspConn)->adspco_PendedSends)) \
  692. { \
  693. writeCtx = LIST_ENTRY_TO_WRITECTX((_pAdspConn)->adspco_PendedSends.Flink); \
  694. writeBufLen = WRITECTX_SIZE(writeCtx); \
  695. \
  696. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN, \
  697. ("AtalkAdspCompleteQueuedSends: %lx WriteLen %x\n", \
  698. writeCtx, writeBufLen)); \
  699. \
  700. RemoveEntryList(WRITECTX_LINKAGE(writeCtx)); \
  701. \
  702. RELEASE_SPIN_LOCK(&(_pAdspConn)->adspco_Lock, OldIrql); \
  703. atalkTdiGenericWriteComplete(_error, \
  704. (PAMDL)(WRITECTX_TDI_BUFFER(writeCtx)), \
  705. (USHORT)writeBufLen, \
  706. WRITECTX(writeCtx)); \
  707. ACQUIRE_SPIN_LOCK(&(_pAdspConn)->adspco_Lock, &OldIrql); \
  708. } \
  709. }
  710. ATALK_ERROR
  711. AtalkAdspDisconnect(
  712. IN PADSP_CONNOBJ pAdspConn,
  713. IN ATALK_DISCONNECT_TYPE DisconnectType,
  714. IN PVOID pDisconnectCtx,
  715. IN GENERIC_COMPLETION DisconnectRoutine
  716. )
  717. /*++
  718. Routine Description:
  719. Arguments:
  720. Return Value:
  721. --*/
  722. {
  723. PAMDL readBuf = NULL,
  724. exReadBuf = NULL;
  725. GENERIC_READ_COMPLETION readCompletion = NULL,
  726. exReadCompletion = NULL;
  727. PVOID readCtx = NULL,
  728. exReadCtx = NULL;
  729. PAMDL exWriteBuf = NULL;
  730. GENERIC_WRITE_COMPLETION exWriteCompletion = NULL;
  731. PVOID exWriteCtx = NULL;
  732. PBYTE exWriteChBuf = NULL,
  733. exRecdBuf = NULL;
  734. GENERIC_COMPLETION completionRoutine = NULL;
  735. PVOID completionCtx = NULL;
  736. ATALK_ERROR error = ATALK_PENDING;
  737. BOOLEAN connTimerCancelled = FALSE,
  738. openTimerCancelled = FALSE,
  739. sendAttnTimerCancelled = FALSE,
  740. rexmitTimerCancelled = FALSE,
  741. connectCancelled = FALSE;
  742. KIRQL OldIrql;
  743. ASSERT(VALID_ADSPCO(pAdspConn));
  744. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  745. ("AtalkAdspDisconnectConnection: %lx.%lx\n", pAdspConn, DisconnectType));
  746. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  747. // Support for graceful disconnect. We only drop the received
  748. // data when the local end does a disconnect. This will happen
  749. // regardless of whether this routine was previously called or
  750. // not. Note that attentions are not acknowledged until our client
  751. // reads them, so there isnt an issue with them. Also, this means
  752. // that we must satisfy a read if disconnect is pending.
  753. if ((DisconnectType == ATALK_LOCAL_DISCONNECT) ||
  754. (DisconnectType == ATALK_TIMER_DISCONNECT))
  755. {
  756. atalkAdspDiscardFromBufferQueue(&pAdspConn->adspco_RecvQueue,
  757. atalkAdspBufferQueueSize(&pAdspConn->adspco_RecvQueue),
  758. NULL,
  759. DISCONN_STATUS(DisconnectType),
  760. NULL);
  761. }
  762. if ((pAdspConn->adspco_Flags & ADSPCO_DISCONNECTING) == 0)
  763. {
  764. if ((pAdspConn->adspco_Flags & (ADSPCO_LISTENING |
  765. ADSPCO_CONNECTING |
  766. ADSPCO_HALF_ACTIVE |
  767. ADSPCO_ACTIVE)) == 0)
  768. {
  769. error = ATALK_INVALID_REQUEST;
  770. }
  771. else
  772. {
  773. pAdspConn->adspco_Flags |= ADSPCO_DISCONNECTING;
  774. if (DisconnectType == ATALK_LOCAL_DISCONNECT)
  775. pAdspConn->adspco_Flags |= ADSPCO_LOCAL_DISCONNECT;
  776. if (DisconnectType == ATALK_REMOTE_DISCONNECT)
  777. pAdspConn->adspco_Flags |= ADSPCO_REMOTE_DISCONNECT;
  778. if (pAdspConn->adspco_Flags & ADSPCO_LISTENING)
  779. {
  780. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  781. AtalkAdspCancelListen(pAdspConn);
  782. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  783. }
  784. else if (pAdspConn->adspco_Flags & ADSPCO_CONNECTING)
  785. {
  786. // Cancel open timer
  787. ASSERT(pAdspConn->adspco_Flags & ADSPCO_OPEN_TIMER);
  788. openTimerCancelled = AtalkTimerCancelEvent(&pAdspConn->adspco_OpenTimer,
  789. NULL);
  790. completionRoutine = pAdspConn->adspco_ConnectCompletion;
  791. completionCtx = pAdspConn->adspco_ConnectCtx;
  792. // We can only be here if the connect is not done yet. Complete
  793. // as if timer is done, always.
  794. pAdspConn->adspco_DisconnectStatus = ATALK_TIMEOUT;
  795. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  796. connectCancelled = atalkAdspConnDeQueueConnectList(pAdspConn->adspco_pAssocAddr,
  797. pAdspConn);
  798. if (!connectCancelled)
  799. {
  800. completionRoutine = NULL;
  801. completionCtx = NULL;
  802. }
  803. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  804. }
  805. // Both of the above could have failed as the connection
  806. // might have become active before the cancel succeeded.
  807. // In that case (or if we were active to begin with), do
  808. // a disconnect here.
  809. if (pAdspConn->adspco_Flags & (ADSPCO_HALF_ACTIVE | ADSPCO_ACTIVE))
  810. {
  811. // Get the completion routines for a pending accept
  812. if (pAdspConn->adspco_Flags & ADSPCO_ACCEPT_IRP)
  813. {
  814. completionRoutine = pAdspConn->adspco_ListenCompletion;
  815. completionCtx = pAdspConn->adspco_ListenCtx;
  816. // Dequeue the open request that must be queued on
  817. // this connection object to filter duplicates.
  818. pAdspConn->adspco_Flags &= ~ADSPCO_ACCEPT_IRP;
  819. }
  820. // First cancel the conection maintainance timer. Only if
  821. // we are not called from the timer.
  822. if ((DisconnectType != ATALK_TIMER_DISCONNECT) &&
  823. (connTimerCancelled =
  824. AtalkTimerCancelEvent(&pAdspConn->adspco_ConnTimer,
  825. NULL)))
  826. {
  827. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  828. ("AtalkAdspDisconnect: Cancelled timer successfully\n"));
  829. }
  830. // Cancel retransmit timer if started. Could be called from
  831. // OpenTimer.
  832. if (pAdspConn->adspco_Flags & ADSPCO_RETRANSMIT_TIMER)
  833. {
  834. rexmitTimerCancelled =
  835. AtalkTimerCancelEvent(&pAdspConn->adspco_RetransmitTimer,
  836. NULL);
  837. }
  838. // Remember completion routines as appropriate.
  839. if (DisconnectType == ATALK_INDICATE_DISCONNECT)
  840. {
  841. if (pAdspConn->adspco_DisconnectInform == NULL)
  842. {
  843. pAdspConn->adspco_DisconnectInform = DisconnectRoutine;
  844. pAdspConn->adspco_DisconnectInformCtx = pDisconnectCtx;
  845. }
  846. else
  847. {
  848. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  849. ("AtalkAdspDisconnect: duplicate disc comp rou%lx\n", pAdspConn));
  850. error = ATALK_TOO_MANY_COMMANDS;
  851. }
  852. }
  853. else if (DisconnectType == ATALK_LOCAL_DISCONNECT)
  854. {
  855. // Replace completion routines only if previous ones are
  856. // NULL.
  857. if (*pAdspConn->adspco_DisconnectCompletion == NULL)
  858. {
  859. pAdspConn->adspco_DisconnectCompletion = DisconnectRoutine;
  860. pAdspConn->adspco_DisconnectCtx = pDisconnectCtx;
  861. }
  862. else
  863. {
  864. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  865. ("AtalkAdspDisconnect: duplicate disc comp rou%lx\n", pAdspConn));
  866. error = ATALK_TOO_MANY_COMMANDS;
  867. }
  868. }
  869. // Figure out the disconnect status and remember it in the
  870. // connection object.
  871. pAdspConn->adspco_DisconnectStatus = DISCONN_STATUS(DisconnectType);
  872. if (pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_RECD)
  873. {
  874. exRecdBuf = pAdspConn->adspco_ExRecdData;
  875. pAdspConn->adspco_Flags &= ~ADSPCO_ATTN_DATA_RECD;
  876. }
  877. // Is there a pending send attention?
  878. if (pAdspConn->adspco_Flags & ADSPCO_EXSEND_IN_PROGRESS)
  879. {
  880. exWriteCompletion = pAdspConn->adspco_ExWriteCompletion;
  881. exWriteCtx = pAdspConn->adspco_ExWriteCtx;
  882. exWriteBuf = pAdspConn->adspco_ExWriteBuf;
  883. exWriteChBuf = pAdspConn->adspco_ExWriteChBuf;
  884. ASSERT(exWriteChBuf != NULL);
  885. sendAttnTimerCancelled =
  886. AtalkTimerCancelEvent(&pAdspConn->adspco_ExRetryTimer,
  887. NULL);
  888. pAdspConn->adspco_Flags &= ~ADSPCO_EXSEND_IN_PROGRESS;
  889. }
  890. // Are there any pending receives?
  891. if (pAdspConn->adspco_Flags & ADSPCO_READ_PENDING)
  892. {
  893. readBuf = pAdspConn->adspco_ReadBuf;
  894. readCompletion = pAdspConn->adspco_ReadCompletion;
  895. readCtx = pAdspConn->adspco_ReadCtx;
  896. pAdspConn->adspco_Flags &= ~ADSPCO_READ_PENDING;
  897. }
  898. if (pAdspConn->adspco_Flags & ADSPCO_EXREAD_PENDING)
  899. {
  900. exReadBuf = pAdspConn->adspco_ExReadBuf;
  901. exReadCompletion = pAdspConn->adspco_ExReadCompletion;
  902. exReadCtx = pAdspConn->adspco_ExReadCtx;
  903. pAdspConn->adspco_Flags &= ~ADSPCO_EXREAD_PENDING;
  904. }
  905. // Discard the send queue. This will complete pending sends.
  906. atalkAdspDiscardFromBufferQueue(&pAdspConn->adspco_SendQueue,
  907. atalkAdspBufferQueueSize(&pAdspConn->adspco_SendQueue),
  908. NULL,
  909. pAdspConn->adspco_DisconnectStatus,
  910. pAdspConn);
  911. atalkAdspCompleteQueuedSends(pAdspConn,
  912. pAdspConn->adspco_DisconnectStatus);
  913. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  914. // Send out disconnect packet if this was a timer or local close.
  915. if ((DisconnectType == ATALK_LOCAL_DISCONNECT) ||
  916. (DisconnectType == ATALK_TIMER_DISCONNECT))
  917. {
  918. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  919. atalkAdspSendControl(pAdspConn,
  920. ADSP_CONTROL_FLAG + ADSP_CLOSE_CONN_CODE);
  921. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  922. }
  923. // Call the send attention completion
  924. if (*exWriteCompletion != NULL)
  925. {
  926. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  927. ("atalkDisconnect: ExWrite\n"));
  928. (*exWriteCompletion)(pAdspConn->adspco_DisconnectStatus,
  929. exWriteBuf,
  930. 0,
  931. exWriteCtx);
  932. AtalkFreeMemory(exWriteChBuf);
  933. }
  934. // If we had received an attention packet, and had
  935. // saved it away, free it.
  936. if (exRecdBuf != NULL)
  937. {
  938. AtalkFreeMemory(exRecdBuf);
  939. }
  940. if (*readCompletion != NULL)
  941. {
  942. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  943. ("atalkDisconnect: Read %lx\n", pAdspConn->adspco_DisconnectStatus));
  944. (*readCompletion)(pAdspConn->adspco_DisconnectStatus,
  945. readBuf,
  946. 0,
  947. 0,
  948. readCtx);
  949. // Deref connection for the read
  950. AtalkAdspConnDereference(pAdspConn);
  951. }
  952. if (*exReadCompletion != NULL)
  953. {
  954. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  955. ("atalkDisconnect: ExRead\n"));
  956. (*exReadCompletion)(pAdspConn->adspco_DisconnectStatus,
  957. exReadBuf,
  958. 0,
  959. 0,
  960. exReadCtx);
  961. // Deref connection for the read
  962. AtalkAdspConnDereference(pAdspConn);
  963. }
  964. // Call the disconnect indication routine if present for a timer/
  965. // remote disconnect.
  966. if ((DisconnectType == ATALK_REMOTE_DISCONNECT) ||
  967. (DisconnectType == ATALK_TIMER_DISCONNECT))
  968. {
  969. PTDI_IND_DISCONNECT discHandler;
  970. PVOID discCtx;
  971. PADSP_ADDROBJ pAdspAddr = pAdspConn->adspco_pAssocAddr;
  972. ASSERT(VALID_ADSPAO(pAdspAddr));
  973. // Acquire lock so we get a consistent handler/ctx.
  974. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  975. discHandler = pAdspAddr->adspao_DisconnectHandler;
  976. discCtx = pAdspAddr->adspao_DisconnectHandlerCtx;
  977. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  978. if (*discHandler != NULL)
  979. {
  980. (*discHandler)(discCtx,
  981. pAdspConn->adspco_ConnCtx,
  982. 0, // DisconnectDataLength
  983. NULL, // DisconnectData
  984. 0, // DisconnectInfoLength
  985. NULL, // DisconnectInfo
  986. TDI_DISCONNECT_ABORT); // Disconnect flags.
  987. }
  988. }
  989. // Stop the ddp address.
  990. AtalkDdpCleanupAddress(pAdspConn->adspco_pDdpAddr);
  991. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  992. }
  993. }
  994. }
  995. else
  996. {
  997. // Do we need to remember the completion routines?
  998. // Yes, if this is a disconnect or a indicate disconnect request,
  999. // and our current disconnect was started due to the address object
  1000. // being closed.
  1001. if (DisconnectType == ATALK_INDICATE_DISCONNECT)
  1002. {
  1003. if (pAdspConn->adspco_DisconnectInform == NULL)
  1004. {
  1005. pAdspConn->adspco_DisconnectInform = DisconnectRoutine;
  1006. pAdspConn->adspco_DisconnectInformCtx = pDisconnectCtx;
  1007. }
  1008. else
  1009. {
  1010. error = ATALK_TOO_MANY_COMMANDS;
  1011. }
  1012. }
  1013. else if (DisconnectType == ATALK_LOCAL_DISCONNECT)
  1014. {
  1015. // Replace completion routines only if previous ones are
  1016. // NULL.
  1017. if (*pAdspConn->adspco_DisconnectCompletion == NULL)
  1018. {
  1019. pAdspConn->adspco_DisconnectCompletion = DisconnectRoutine;
  1020. pAdspConn->adspco_DisconnectCtx = pDisconnectCtx;
  1021. }
  1022. else
  1023. {
  1024. error = ATALK_TOO_MANY_COMMANDS;
  1025. }
  1026. }
  1027. }
  1028. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  1029. // If there was a completion routine to call, call it now.
  1030. if (*completionRoutine != NULL)
  1031. {
  1032. (*completionRoutine)(pAdspConn->adspco_DisconnectStatus,
  1033. completionCtx);
  1034. }
  1035. // If we cancelled any timers, remove their references.
  1036. if (connTimerCancelled)
  1037. {
  1038. AtalkAdspConnDereference(pAdspConn);
  1039. }
  1040. if (sendAttnTimerCancelled)
  1041. {
  1042. AtalkAdspConnDereference(pAdspConn);
  1043. }
  1044. if (openTimerCancelled)
  1045. {
  1046. AtalkAdspConnDereference(pAdspConn);
  1047. }
  1048. if (rexmitTimerCancelled)
  1049. {
  1050. AtalkAdspConnDereference(pAdspConn);
  1051. }
  1052. return error;
  1053. }
  1054. ATALK_ERROR
  1055. AtalkAdspRead(
  1056. IN PADSP_CONNOBJ pAdspConn,
  1057. IN PAMDL pReadBuf,
  1058. IN USHORT ReadBufLen,
  1059. IN ULONG ReadFlags,
  1060. IN PVOID pReadCtx,
  1061. IN GENERIC_READ_COMPLETION CompletionRoutine
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Arguments:
  1066. Return Value:
  1067. --*/
  1068. {
  1069. KIRQL OldIrql;
  1070. ATALK_ERROR error;
  1071. ASSERT(VALID_ADSPCO(pAdspConn));
  1072. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  1073. do
  1074. {
  1075. // We allow reads when disconnecting if the receive data
  1076. // queue is non-empty. Since none of the receive chunks ref
  1077. // the connection, the active flag and the disconnect
  1078. // flags could have gone away. So we cue of the receive buffer
  1079. // size. We also dont allow exdata recvs unless we are active.
  1080. if (((pAdspConn->adspco_Flags & (ADSPCO_CLOSING | ADSPCO_STOPPING))) ||
  1081. ((((pAdspConn->adspco_Flags & ADSPCO_ACTIVE) == 0) ||
  1082. (pAdspConn->adspco_Flags & ADSPCO_DISCONNECTING)) &&
  1083. (((atalkAdspBufferQueueSize(&pAdspConn->adspco_RecvQueue) == 0)) ||
  1084. (ReadFlags & TDI_RECEIVE_EXPEDITED))))
  1085. {
  1086. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  1087. ("AtalkAdspRead: Failing on %lx Flg %lx.%lx\n",
  1088. pAdspConn, pAdspConn->adspco_Flags, ReadFlags));
  1089. error = ATALK_ADSP_CONN_NOT_ACTIVE;
  1090. break;
  1091. }
  1092. // Depending on the kind of read we are posting...
  1093. if (((ReadFlags & TDI_RECEIVE_NORMAL) &&
  1094. (pAdspConn->adspco_Flags & ADSPCO_READ_PENDING)) ||
  1095. ((ReadFlags & TDI_RECEIVE_EXPEDITED) &&
  1096. (pAdspConn->adspco_Flags & ADSPCO_EXREAD_PENDING)))
  1097. {
  1098. error = ATALK_TOO_MANY_COMMANDS;
  1099. break;
  1100. }
  1101. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 1, &error);
  1102. if (!ATALK_SUCCESS(error))
  1103. {
  1104. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1105. ("AtalkAdspRead: ConnRef Failing on %lx Flg %lx.%lx\n",
  1106. pAdspConn, pAdspConn->adspco_Flags, ReadFlags));
  1107. break;
  1108. }
  1109. // Remember the read completion information
  1110. if (ReadFlags & TDI_RECEIVE_NORMAL)
  1111. {
  1112. pAdspConn->adspco_Flags |= ADSPCO_READ_PENDING;
  1113. pAdspConn->adspco_ReadFlags = ReadFlags;
  1114. pAdspConn->adspco_ReadBuf = pReadBuf;
  1115. pAdspConn->adspco_ReadBufLen = ReadBufLen;
  1116. pAdspConn->adspco_ReadCompletion = CompletionRoutine;
  1117. pAdspConn->adspco_ReadCtx = pReadCtx;
  1118. }
  1119. else
  1120. {
  1121. ASSERT(ReadFlags & TDI_RECEIVE_EXPEDITED);
  1122. pAdspConn->adspco_Flags |= ADSPCO_EXREAD_PENDING;
  1123. pAdspConn->adspco_ExReadFlags = ReadFlags;
  1124. pAdspConn->adspco_ExReadBuf = pReadBuf;
  1125. pAdspConn->adspco_ExReadBufLen = ReadBufLen;
  1126. pAdspConn->adspco_ExReadCompletion = CompletionRoutine;
  1127. pAdspConn->adspco_ExReadCtx = pReadCtx;
  1128. }
  1129. } while (FALSE);
  1130. if (ATALK_SUCCESS(error))
  1131. {
  1132. // Try to complete the read. This will also handle received
  1133. // attention data.
  1134. atalkAdspRecvData(pAdspConn);
  1135. error = ATALK_PENDING;
  1136. }
  1137. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  1138. return error;
  1139. }
  1140. VOID
  1141. AtalkAdspProcessQueuedSend(
  1142. IN PADSP_CONNOBJ pAdspConn
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. Arguments:
  1147. Return Value:
  1148. --*/
  1149. {
  1150. ULONG sendSize, windowSize, writeBufLen, writeFlags;
  1151. KIRQL OldIrql;
  1152. PVOID writeCtx;
  1153. ATALK_ERROR error;
  1154. BOOLEAN eom;
  1155. PBUFFER_CHUNK pChunk = NULL;
  1156. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  1157. PVOID sendPossibleHandlerCtx;
  1158. // Walk through pended list.
  1159. while (!IsListEmpty(&pAdspConn->adspco_PendedSends))
  1160. {
  1161. writeCtx = LIST_ENTRY_TO_WRITECTX(pAdspConn->adspco_PendedSends.Flink);
  1162. writeBufLen = WRITECTX_SIZE(writeCtx);
  1163. writeFlags = WRITECTX_FLAGS(writeCtx);
  1164. eom = (writeFlags & TDI_SEND_PARTIAL) ? FALSE : TRUE;
  1165. eom = (eom && (pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_MESSAGE));
  1166. windowSize = (LONG)(pAdspConn->adspco_SendWindowSeq -
  1167. pAdspConn->adspco_SendSeq +
  1168. (LONG)1);
  1169. sendSize = MIN(atalkAdspMaxSendSize(pAdspConn), windowSize);
  1170. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  1171. ("AtalkAdspProcessQueuedSend: %lx SendSize %lx, WriteBufLen %x Flags %lx\n",
  1172. writeCtx, sendSize, writeBufLen, writeFlags));
  1173. // While looping through requests, we might exhaust window.
  1174. if (sendSize == 0)
  1175. {
  1176. // Call send possible handler indicating sends are not ok.
  1177. // Needs to be within spinlock to avoid raceconditions where
  1178. // an ack has come in and opened the window. And it needs to
  1179. // be before atalkAdspSendData() as that will release the lock.
  1180. sendPossibleHandler =
  1181. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandler;
  1182. sendPossibleHandlerCtx =
  1183. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandlerCtx;
  1184. if (*sendPossibleHandler != NULL)
  1185. {
  1186. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  1187. pAdspConn->adspco_ConnCtx,
  1188. 0);
  1189. pAdspConn->adspco_Flags |= ADSPCO_SEND_WINDOW_CLOSED;
  1190. }
  1191. break;
  1192. }
  1193. // !!! The client can do a send with 0 bytes and eom only also.
  1194. if ((ULONG)(writeBufLen + BYTECOUNT(eom)) > sendSize)
  1195. {
  1196. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  1197. ("AtalkAdspProcessQueuedSend: WriteBufLen %lx > sendsize %lx\n",
  1198. writeBufLen, sendSize));
  1199. // Adjust send to send as much as it can. Winsock loop will pend
  1200. // it again with remaining data.
  1201. writeBufLen = (USHORT)(sendSize - BYTECOUNT(eom));
  1202. // If we hit the weird case where now we are trying to send 0 bytes and
  1203. // no eom, while the actual send does have an eom, then we just wait
  1204. // for window to open up more.
  1205. if (eom && (writeBufLen == 0))
  1206. {
  1207. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1208. ("AtalkAdspProcessQueuedSend: WriteBufLen %lx.%d.%lx %lx\n",
  1209. writeBufLen, eom, sendSize, pAdspConn));
  1210. break;
  1211. }
  1212. ASSERT(writeBufLen > 0);
  1213. eom = FALSE;
  1214. }
  1215. ASSERT((writeBufLen > 0) || eom);
  1216. // Yippee, can send it now. Either it goes in send queue or is completed
  1217. // right away.
  1218. RemoveEntryList(WRITECTX_LINKAGE(writeCtx));
  1219. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  1220. ("AtalkAdspProcessQueuedSend: Processing queued send %lx.%lx\n",
  1221. pAdspConn, writeCtx));
  1222. // Think positive! Assume everything will go well and allocate
  1223. // the buffer chunk that would be needed for this data. Copy the
  1224. // data into the buffer chunk. We cant do this in the beginning as
  1225. // we need to get WriteBufLen set up.
  1226. pChunk = (PBUFFER_CHUNK)
  1227. atalkAdspAllocCopyChunk((PAMDL)(WRITECTX_TDI_BUFFER(writeCtx)),
  1228. (USHORT)writeBufLen,
  1229. eom,
  1230. FALSE);
  1231. error = ATALK_RESR_MEM;
  1232. if (pChunk != NULL)
  1233. {
  1234. // Set the completion information in the chunk. This will
  1235. // be called when the last reference on the chunk goes away.
  1236. pChunk->bc_Flags |= BC_SEND;
  1237. pChunk->bc_WriteBuf = (PAMDL)(WRITECTX_TDI_BUFFER(writeCtx));
  1238. pChunk->bc_WriteCompletion = atalkTdiGenericWriteComplete;
  1239. pChunk->bc_WriteCtx = writeCtx;
  1240. pChunk->bc_ConnObj = pAdspConn;
  1241. atalkAdspAddToBufferQueue(&pAdspConn->adspco_SendQueue,
  1242. pChunk,
  1243. &pAdspConn->adspco_NextSendQueue);
  1244. // Try to send the data
  1245. atalkAdspSendData(pAdspConn);
  1246. error = ATALK_PENDING;
  1247. }
  1248. if (!ATALK_SUCCESS(error))
  1249. {
  1250. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1251. ("AtalkAdspProcessQueuedSend: Error queued send %lx.%lx\n",
  1252. pAdspConn, writeCtx));
  1253. #if DBG
  1254. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  1255. #endif
  1256. // Complete send request with insufficient resources error.
  1257. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  1258. atalkTdiGenericWriteComplete(error,
  1259. (PAMDL)(WRITECTX_TDI_BUFFER(writeCtx)),
  1260. (USHORT)writeBufLen,
  1261. WRITECTX(writeCtx));
  1262. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  1263. #if DBG
  1264. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  1265. #endif
  1266. }
  1267. }
  1268. }
  1269. ATALK_ERROR
  1270. AtalkAdspWrite(
  1271. IN PADSP_CONNOBJ pAdspConn,
  1272. IN PAMDL pWriteBuf,
  1273. IN USHORT WriteBufLen,
  1274. IN ULONG SendFlags,
  1275. IN PVOID pWriteCtx,
  1276. IN GENERIC_WRITE_COMPLETION CompletionRoutine
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Arguments:
  1281. Return Value:
  1282. --*/
  1283. {
  1284. ATALK_ERROR error;
  1285. BOOLEAN eom;
  1286. ULONG sendSize, windowSize;
  1287. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  1288. PVOID sendPossibleHandlerCtx;
  1289. KIRQL OldIrql;
  1290. PBUFFER_CHUNK pChunk = NULL;
  1291. BOOLEAN DerefConn = FALSE,
  1292. callComp = FALSE;
  1293. ASSERT(VALID_ADSPCO(pAdspConn));
  1294. eom = (SendFlags & TDI_SEND_PARTIAL) ? FALSE : TRUE;
  1295. if ((WriteBufLen == 0) && !eom)
  1296. {
  1297. return ATALK_BUFFER_TOO_SMALL;
  1298. }
  1299. if (SendFlags & TDI_SEND_EXPEDITED)
  1300. {
  1301. return (atalkAdspSendExpedited(pAdspConn,
  1302. pWriteBuf,
  1303. WriteBufLen,
  1304. SendFlags,
  1305. pWriteCtx,
  1306. CompletionRoutine));
  1307. }
  1308. // We atleast have one byte of data or eom to send.
  1309. ASSERT(eom || (WriteBufLen != 0));
  1310. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  1311. do
  1312. {
  1313. if ((pAdspConn->adspco_Flags & (ADSPCO_ACTIVE |
  1314. ADSPCO_CLOSING |
  1315. ADSPCO_STOPPING |
  1316. ADSPCO_DISCONNECTING)) != ADSPCO_ACTIVE)
  1317. {
  1318. error = ATALK_ADSP_CONN_NOT_ACTIVE;
  1319. break;
  1320. }
  1321. if (pAdspConn->adspco_Flags & ADSPCO_SEND_IN_PROGRESS)
  1322. {
  1323. error = ATALK_TOO_MANY_COMMANDS;
  1324. break;
  1325. }
  1326. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 1, &error);
  1327. if (!ATALK_SUCCESS(error))
  1328. {
  1329. break;
  1330. }
  1331. eom = (eom && (pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_MESSAGE));
  1332. DerefConn = TRUE;
  1333. windowSize = (LONG)(pAdspConn->adspco_SendWindowSeq -
  1334. pAdspConn->adspco_SendSeq +
  1335. (LONG)1);
  1336. sendSize = MIN(atalkAdspMaxSendSize(pAdspConn), windowSize);
  1337. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1338. ("AtalkAdspWrite: SendSize %lx, WriteBufLen %x\n", sendSize, WriteBufLen));
  1339. // For a blocking send, queue in any sends that exceed window size.
  1340. if ((SendFlags & TDI_SEND_NON_BLOCKING) == 0)
  1341. {
  1342. if ((!IsListEmpty(&pAdspConn->adspco_PendedSends)) ||
  1343. (sendSize < (WriteBufLen + BYTECOUNT(eom))))
  1344. {
  1345. // Stop sends whenever a send gets queued.
  1346. sendPossibleHandler =
  1347. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandler;
  1348. sendPossibleHandlerCtx =
  1349. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandlerCtx;
  1350. if (*sendPossibleHandler != NULL)
  1351. {
  1352. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  1353. pAdspConn->adspco_ConnCtx,
  1354. 0);
  1355. pAdspConn->adspco_Flags |= ADSPCO_SEND_WINDOW_CLOSED;
  1356. }
  1357. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1358. ("AtalkAdspWrite: Wdw %lx, WriteLen %x on BLOCKING QUEUEING !\n",
  1359. sendSize, WriteBufLen));
  1360. InsertTailList(&pAdspConn->adspco_PendedSends, WRITECTX_LINKAGE(pWriteCtx));
  1361. if (sendSize > 0)
  1362. {
  1363. AtalkAdspProcessQueuedSend(pAdspConn);
  1364. }
  1365. error = ATALK_PENDING;
  1366. break;
  1367. }
  1368. }
  1369. else
  1370. {
  1371. // If there are pended blocking sends complete them with
  1372. // ATALK_REQUEST_NOT_ACCEPTED (WSAEWOULDBLOCK).
  1373. //
  1374. // !!!This is data corruption, but app shouldn't be doing this.
  1375. //
  1376. if (!IsListEmpty(&pAdspConn->adspco_PendedSends))
  1377. {
  1378. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1379. ("AtalkAdspWrite: ABORTING PENDED SENDS CORRUPTION %lx\n", pAdspConn));
  1380. atalkAdspCompleteQueuedSends(pAdspConn, ATALK_REQUEST_NOT_ACCEPTED);
  1381. }
  1382. }
  1383. if (sendSize == 0)
  1384. {
  1385. // Call send possible handler indicating sends are not ok.
  1386. // Needs to be within spinlock to avoid raceconditions where
  1387. // an ack has come in and opened the window. And it needs to
  1388. // be before atalkAdspSendData() as that will release the lock.
  1389. sendPossibleHandler =
  1390. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandler;
  1391. sendPossibleHandlerCtx =
  1392. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandlerCtx;
  1393. if (*sendPossibleHandler != NULL)
  1394. {
  1395. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  1396. pAdspConn->adspco_ConnCtx,
  1397. 0);
  1398. pAdspConn->adspco_Flags |= ADSPCO_SEND_WINDOW_CLOSED;
  1399. }
  1400. if (SendFlags & TDI_SEND_NON_BLOCKING)
  1401. {
  1402. // !!!NOTE!!!
  1403. // To avoid the race condition in AFD where an incoming
  1404. // send data indication setting send's possible to true
  1405. // is overwritten by this read's unwinding and setting it
  1406. // to false, we return ATALK_REQUEST_NOT_ACCEPTED, which
  1407. // will map to STATUS_REQUEST_NOT_ACCEPTED and then to
  1408. // WSAEWOULDBLOCK.
  1409. // error = ATALK_DEVICE_NOT_READY;
  1410. error = ATALK_REQUEST_NOT_ACCEPTED;
  1411. }
  1412. // We have no open send window, try to send data in the retransmit
  1413. // queue.
  1414. atalkAdspSendData(pAdspConn);
  1415. break;
  1416. }
  1417. // Because of the sequence numbers, we need to copy the data
  1418. // into our buffers while holding the spinlock. If we cant send it all
  1419. // send as much as we can.
  1420. // !!! TDI doesn't count the eom as taking up a count, so we need to
  1421. // make allowances for that. If we are able to send just the data
  1422. // but not the eom, we should send one less byte than requested, so
  1423. // the client retries again.
  1424. // !!! The client can do a send with 0 bytes and eom only also.
  1425. if ((ULONG)(WriteBufLen + BYTECOUNT(eom)) > sendSize)
  1426. {
  1427. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1428. ("AtalkAdspSend: WriteBufLen being decreased %x.%lx\n",
  1429. WriteBufLen, sendSize-BYTECOUNT(eom)));
  1430. WriteBufLen = (USHORT)(sendSize - BYTECOUNT(eom));
  1431. eom = FALSE;
  1432. }
  1433. if ((WriteBufLen == 0) && !eom)
  1434. {
  1435. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1436. ("AtalkAdspSend: SEND 0 bytes NO EOM %lx\n", pAdspConn));
  1437. callComp = TRUE;
  1438. error = ATALK_PENDING;
  1439. break;
  1440. }
  1441. // pAdspConn->adspco_Flags |= ADSPCO_SEND_IN_PROGRESS;
  1442. // If we release the spin lock here we have a race condition
  1443. // where the sendsize is still not accounting for this send,
  1444. // and so another posted send could come in when it really
  1445. // shouldn't. We avoid it using the flag above, which when
  1446. // set will prevent further sends from happening.
  1447. // RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  1448. // Think positive! Assume everything will go well and allocate
  1449. // the buffer chunk that would be needed for this data. Copy the
  1450. // data into the buffer chunk. We cant do this in the beginning as
  1451. // we need to get WriteBufLen set up.
  1452. pChunk = (PBUFFER_CHUNK)atalkAdspAllocCopyChunk(pWriteBuf,
  1453. WriteBufLen,
  1454. eom,
  1455. FALSE);
  1456. // ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  1457. // pAdspConn->adspco_Flags &= ~ADSPCO_SEND_IN_PROGRESS;
  1458. error = ATALK_RESR_MEM;
  1459. if (pChunk != NULL)
  1460. {
  1461. // Set the completion information in the chunk. This will
  1462. // be called when the last reference on the chunk goes away.
  1463. pChunk->bc_Flags |= BC_SEND;
  1464. pChunk->bc_WriteBuf = pWriteBuf;
  1465. pChunk->bc_WriteCompletion = CompletionRoutine;
  1466. pChunk->bc_WriteCtx = pWriteCtx;
  1467. pChunk->bc_ConnObj = pAdspConn;
  1468. atalkAdspAddToBufferQueue(&pAdspConn->adspco_SendQueue,
  1469. pChunk,
  1470. &pAdspConn->adspco_NextSendQueue);
  1471. // Try to send the data
  1472. atalkAdspSendData(pAdspConn);
  1473. error = ATALK_PENDING;
  1474. }
  1475. } while (FALSE);
  1476. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  1477. if ((error == ATALK_PENDING) && callComp)
  1478. {
  1479. ASSERT(WriteBufLen == 0);
  1480. ASSERT(pChunk == NULL);
  1481. (*CompletionRoutine)(ATALK_NO_ERROR,
  1482. pWriteBuf,
  1483. WriteBufLen,
  1484. pWriteCtx);
  1485. }
  1486. else if (!ATALK_SUCCESS(error) && (pChunk != NULL))
  1487. {
  1488. AtalkFreeMemory(pChunk);
  1489. }
  1490. if (DerefConn)
  1491. {
  1492. AtalkAdspConnDereference(pAdspConn);
  1493. }
  1494. return error;
  1495. }
  1496. VOID
  1497. AtalkAdspQuery(
  1498. IN PVOID pObject,
  1499. IN ULONG ObjectType,
  1500. IN PAMDL pAmdl,
  1501. OUT PULONG BytesWritten
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. Arguments:
  1506. Return Value:
  1507. --*/
  1508. {
  1509. switch (ObjectType)
  1510. {
  1511. case TDI_TRANSPORT_ADDRESS_FILE :
  1512. ASSERT(VALID_ADSPAO((PADSP_ADDROBJ)pObject));
  1513. AtalkDdpQuery(AtalkAdspGetDdpAddress((PADSP_ADDROBJ)pObject),
  1514. pAmdl,
  1515. BytesWritten);
  1516. break;
  1517. case TDI_CONNECTION_FILE :
  1518. {
  1519. KIRQL OldIrql;
  1520. PADSP_CONNOBJ pAdspConn;
  1521. pAdspConn = (PADSP_CONNOBJ)pObject;
  1522. ASSERT(VALID_ADSPCO(pAdspConn));
  1523. *BytesWritten = 0;
  1524. // Get the address from the associated address if any.
  1525. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  1526. if (pAdspConn->adspco_Flags & ADSPCO_ASSOCIATED)
  1527. {
  1528. AtalkDdpQuery(AtalkAdspGetDdpAddress(pAdspConn->adspco_pAssocAddr),
  1529. pAmdl,
  1530. BytesWritten);
  1531. }
  1532. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  1533. }
  1534. break;
  1535. case TDI_CONTROL_CHANNEL_FILE :
  1536. default:
  1537. break;
  1538. }
  1539. }
  1540. //
  1541. // ADSP PACKET IN (HANDLE ROUTINES)
  1542. //
  1543. VOID
  1544. atalkAdspPacketIn(
  1545. IN PPORT_DESCRIPTOR pPortDesc,
  1546. IN PDDP_ADDROBJ pDdpAddr,
  1547. IN PBYTE pPkt,
  1548. IN USHORT PktLen,
  1549. IN PATALK_ADDR pSrcAddr,
  1550. IN PATALK_ADDR pDestAddr,
  1551. IN ATALK_ERROR ErrorCode,
  1552. IN BYTE DdpType,
  1553. IN PADSP_ADDROBJ pAdspAddr,
  1554. IN BOOLEAN OptimizedPath,
  1555. IN PVOID OptimizeCtx
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. Arguments:
  1560. Return Value:
  1561. --*/
  1562. {
  1563. ATALK_ERROR error;
  1564. PADSP_CONNOBJ pAdspConn;
  1565. USHORT remoteConnId;
  1566. ULONG remoteFirstByteSeq, remoteNextRecvSeq;
  1567. LONG remoteRecvWindow;
  1568. BYTE descriptor, controlCode;
  1569. BOOLEAN DerefConn = FALSE;
  1570. do
  1571. {
  1572. if ((!ATALK_SUCCESS(ErrorCode)) ||
  1573. (DdpType != DDPPROTO_ADSP) ||
  1574. (PktLen < ADSP_DATA_OFF))
  1575. {
  1576. ASSERT(0);
  1577. break;
  1578. }
  1579. // Decode the header.
  1580. atalkAdspDecodeHeader(pPkt,
  1581. &remoteConnId,
  1582. &remoteFirstByteSeq,
  1583. &remoteNextRecvSeq,
  1584. &remoteRecvWindow,
  1585. &descriptor);
  1586. controlCode = (descriptor & ADSP_CONTROL_MASK);
  1587. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1588. ("atalkAdspPacketIn: Recd packet %lx.%x\n", remoteConnId, descriptor));
  1589. // If this is a open connection request we handle it in here,
  1590. // else we find the connection it is meant for and pass it on.
  1591. if ((descriptor & ADSP_CONTROL_FLAG) &&
  1592. (controlCode == ADSP_OPENCONN_REQ_CODE))
  1593. {
  1594. // Handle the open connection.
  1595. if (PktLen < (ADSP_NEXT_ATTEN_SEQNUM_OFF + sizeof(ULONG)))
  1596. {
  1597. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1598. ("atalkAdspPacketIn: Incorrect len for pkt\n"));
  1599. break;
  1600. }
  1601. atalkAdspHandleOpenReq(pAdspAddr,
  1602. pPkt,
  1603. PktLen,
  1604. pSrcAddr,
  1605. remoteConnId,
  1606. remoteFirstByteSeq,
  1607. remoteNextRecvSeq,
  1608. remoteRecvWindow,
  1609. descriptor);
  1610. break;
  1611. }
  1612. if ((descriptor & ADSP_CONTROL_FLAG) &&
  1613. (controlCode > ADSP_OPENCONN_REQ_CODE) &&
  1614. (controlCode <= ADSP_OPENCONN_DENY_CODE))
  1615. {
  1616. // Handle the open connection.
  1617. if (PktLen < (ADSP_NEXT_ATTEN_SEQNUM_OFF + sizeof(ULONG)))
  1618. {
  1619. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1620. ("atalkAdspPacketIn: Incorrect len for pkt\n"));
  1621. break;
  1622. }
  1623. atalkAdspHandleOpenControl(pAdspAddr,
  1624. pPkt,
  1625. PktLen,
  1626. pSrcAddr,
  1627. remoteConnId,
  1628. remoteFirstByteSeq,
  1629. remoteNextRecvSeq,
  1630. remoteRecvWindow,
  1631. descriptor);
  1632. break;
  1633. }
  1634. // This was not an open connection request, find the connection
  1635. // this is meant for.
  1636. ACQUIRE_SPIN_LOCK_DPC(&pAdspAddr->adspao_Lock);
  1637. atalkAdspConnRefBySrcAddr(pAdspAddr,
  1638. pSrcAddr,
  1639. remoteConnId,
  1640. &pAdspConn,
  1641. &error);
  1642. RELEASE_SPIN_LOCK_DPC(&pAdspAddr->adspao_Lock);
  1643. if (!ATALK_SUCCESS(error))
  1644. {
  1645. // Not one of our active/half open connections.
  1646. break;
  1647. }
  1648. DerefConn = TRUE;
  1649. pAdspConn->adspco_LastContactTime = AtalkGetCurrentTick();
  1650. if (descriptor & ADSP_ATTEN_FLAG)
  1651. {
  1652. // Handle attention packets
  1653. atalkAdspHandleAttn(pAdspConn,
  1654. pPkt,
  1655. PktLen,
  1656. pSrcAddr,
  1657. remoteFirstByteSeq,
  1658. remoteNextRecvSeq,
  1659. remoteRecvWindow,
  1660. descriptor);
  1661. break;
  1662. }
  1663. // Check if we got a piggybacked ack. This will call the
  1664. // send possible handler too if the send window opens up.
  1665. // It will also change the send sequence number.
  1666. atalkAdspHandlePiggyBackAck(pAdspConn,
  1667. remoteNextRecvSeq,
  1668. remoteRecvWindow);
  1669. if (descriptor & ADSP_CONTROL_FLAG)
  1670. {
  1671. // Handle the other control packets
  1672. atalkAdspHandleControl(pAdspConn,
  1673. pPkt,
  1674. PktLen,
  1675. pSrcAddr,
  1676. remoteFirstByteSeq,
  1677. remoteNextRecvSeq,
  1678. remoteRecvWindow,
  1679. descriptor);
  1680. break;
  1681. }
  1682. // If we got something that didnt fit any of the above, we might
  1683. // have some data.
  1684. atalkAdspHandleData(pAdspConn,
  1685. pPkt,
  1686. PktLen,
  1687. pSrcAddr,
  1688. remoteFirstByteSeq,
  1689. remoteNextRecvSeq,
  1690. remoteRecvWindow,
  1691. descriptor);
  1692. } while (FALSE);
  1693. if (DerefConn)
  1694. {
  1695. AtalkAdspConnDereference(pAdspConn);
  1696. }
  1697. }
  1698. LOCAL VOID
  1699. atalkAdspHandleOpenControl(
  1700. IN PADSP_ADDROBJ pAdspAddr,
  1701. IN PBYTE pPkt,
  1702. IN USHORT PktLen,
  1703. IN PATALK_ADDR pSrcAddr,
  1704. IN USHORT RemoteConnId,
  1705. IN ULONG RemoteFirstByteSeq,
  1706. IN ULONG RemoteNextRecvSeq,
  1707. IN ULONG RemoteRecvWindow,
  1708. IN BYTE Descriptor
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. !!!WE ONLY SUPPORT THE LISTENER PARADIGM FOR CONNECTION ESTABLISHMENT!!!
  1713. !!!A OpenConnectionRequest will always open a new connection! Remote !!!
  1714. !!!MUST send a Open Connection Request & Acknowledgement !!!
  1715. Arguments:
  1716. Return Value:
  1717. --*/
  1718. {
  1719. PADSP_CONNOBJ pAdspConn;
  1720. BYTE controlCode;
  1721. USHORT adspVersionStamp, destConnId;
  1722. KIRQL OldIrql;
  1723. ULONG recvAttnSeq;
  1724. PADSP_OPEN_REQ pOpenReq = NULL;
  1725. ATALK_ERROR error = ATALK_NO_ERROR;
  1726. GENERIC_COMPLETION completionRoutine = NULL;
  1727. PVOID completionCtx = NULL;
  1728. BOOLEAN sendAck = FALSE,
  1729. openTimerCancelled = FALSE,
  1730. relAddrLock = FALSE;
  1731. PTDI_IND_SEND_POSSIBLE sendPossibleHandler = NULL;
  1732. PVOID sendPossibleHandlerCtx;
  1733. controlCode = (Descriptor & ADSP_CONTROL_MASK);
  1734. ASSERT(controlCode != ADSP_OPENCONN_REQ_CODE);
  1735. // Get the other information from the adsp header
  1736. GETSHORT2SHORT(&adspVersionStamp,
  1737. pPkt + ADSP_VERSION_STAMP_OFF);
  1738. GETSHORT2SHORT(&destConnId,
  1739. pPkt + ADSP_DEST_CONNID_OFF);
  1740. GETDWORD2DWORD(&recvAttnSeq,
  1741. pPkt + ADSP_NEXT_ATTEN_SEQNUM_OFF);
  1742. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1743. ("atalkAdspHandleOpenControl: OpenControl %lx.%lx.%lx.%lx.%lx\n",
  1744. RemoteConnId, RemoteFirstByteSeq, RemoteNextRecvSeq, RemoteRecvWindow, recvAttnSeq));
  1745. // Drop request if version isnt right.
  1746. if (adspVersionStamp != ADSP_VERSION)
  1747. {
  1748. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  1749. ("atalkAdspPacketIn: Version incorrect\n"));
  1750. return;
  1751. }
  1752. // Find the connection, since this could be a deny, we cant
  1753. // use the remote values as they would not be valid. The
  1754. // connection should be in the connecting list for a reqandack/deny.
  1755. // For ack the remote values should be valid and the
  1756. // connection will be in the active list with the flags indicating
  1757. // that it is only half open.
  1758. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  1759. relAddrLock = TRUE;
  1760. if (controlCode == ADSP_OPENCONN_ACK_CODE)
  1761. {
  1762. // The connection will be in the active list.
  1763. atalkAdspConnRefBySrcAddr(pAdspAddr,
  1764. pSrcAddr,
  1765. RemoteConnId,
  1766. &pAdspConn,
  1767. &error);
  1768. }
  1769. else
  1770. {
  1771. atalkAdspConnFindInConnect(pAdspAddr,
  1772. destConnId,
  1773. pSrcAddr,
  1774. &pAdspConn,
  1775. &error);
  1776. }
  1777. if (ATALK_SUCCESS(error))
  1778. {
  1779. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  1780. switch (controlCode)
  1781. {
  1782. case ADSP_OPENCONN_DENY_CODE:
  1783. // Cancel open timer if this was a CONNECTING connection. If
  1784. // we had send out a ACK&REQ and then received a DENY just drop
  1785. // this and let the connection age out.
  1786. if ((pAdspConn->adspco_Flags & ADSPCO_CONNECTING) &&
  1787. ((pAdspConn->adspco_Flags & ADSPCO_DISCONNECTING) == 0))
  1788. {
  1789. ASSERT(pAdspConn->adspco_Flags & ADSPCO_OPEN_TIMER);
  1790. // Turn of the connecting flag as we are completing the request.
  1791. // If OpenTimer calls disconnect, then we wont end up trying to
  1792. // complete the request twice.
  1793. pAdspConn->adspco_Flags &= ~ADSPCO_CONNECTING;
  1794. openTimerCancelled = AtalkTimerCancelEvent(&pAdspConn->adspco_OpenTimer,
  1795. NULL);
  1796. // Connection Denied.
  1797. atalkAdspConnDeQueueConnectList(pAdspAddr, pAdspConn);
  1798. completionRoutine = pAdspConn->adspco_ConnectCompletion;
  1799. completionCtx = pAdspConn->adspco_ConnectCtx;
  1800. error = ATALK_ADSP_SERVER_BUSY;
  1801. }
  1802. break;
  1803. case ADSP_OPENCONN_REQANDACK_CODE:
  1804. // Connection Request Accepted By Remote. If we are disconnecting
  1805. // drop this.
  1806. if ((pAdspConn->adspco_Flags & (ADSPCO_SEEN_REMOTE_OPEN |
  1807. ADSPCO_DISCONNECTING)) == 0)
  1808. {
  1809. ULONG index;
  1810. // If the connecting connection has not already seen
  1811. // the remote open request, then get all the relevent
  1812. // remote info for the connection.
  1813. pAdspConn->adspco_Flags |= (ADSPCO_SEEN_REMOTE_OPEN |
  1814. ADSPCO_HALF_ACTIVE);
  1815. atalkAdspConnDeQueueConnectList(pAdspAddr, pAdspConn);
  1816. pAdspConn->adspco_RemoteConnId = RemoteConnId;
  1817. pAdspConn->adspco_RemoteAddr = *pSrcAddr;
  1818. pAdspConn->adspco_SendSeq = RemoteNextRecvSeq;
  1819. pAdspConn->adspco_FirstRtmtSeq = RemoteNextRecvSeq;
  1820. pAdspConn->adspco_RecvAttnSeq = recvAttnSeq;
  1821. pAdspConn->adspco_SendWindowSeq = RemoteNextRecvSeq +
  1822. RemoteRecvWindow -
  1823. (ULONG)1;
  1824. // Thread the connection object into addr lookup by session id.
  1825. index = HASH_ID_SRCADDR(RemoteConnId, pSrcAddr);
  1826. index %= ADSP_CONN_HASH_SIZE;
  1827. pAdspConn->adspco_pNextActive = pAdspAddr->adspao_pActiveHash[index];
  1828. pAdspAddr->adspao_pActiveHash[index] = pAdspConn;
  1829. }
  1830. else
  1831. {
  1832. // We've already seen the remote request.
  1833. break;
  1834. }
  1835. case ADSP_OPENCONN_ACK_CODE:
  1836. // Ensure we are not closing, so we can reference properly. Drop
  1837. // if we are disconnecting.
  1838. if ((pAdspConn->adspco_Flags & ADSPCO_HALF_ACTIVE) &&
  1839. ((pAdspConn->adspco_Flags & ( ADSPCO_DISCONNECTING |
  1840. ADSPCO_STOPPING |
  1841. ADSPCO_CLOSING)) == 0))
  1842. {
  1843. // Cancel open timer
  1844. ASSERT(pAdspConn->adspco_Flags & ADSPCO_OPEN_TIMER);
  1845. openTimerCancelled = AtalkTimerCancelEvent(&pAdspConn->adspco_OpenTimer,
  1846. NULL);
  1847. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1848. ("atalkAdspHandleOpenControl: OpenTimer %d\n", openTimerCancelled));
  1849. pAdspConn->adspco_Flags &= ~(ADSPCO_HALF_ACTIVE |
  1850. ADSPCO_CONNECTING |
  1851. ADSPCO_LISTENING);
  1852. pAdspConn->adspco_Flags |= ADSPCO_ACTIVE;
  1853. // Prepare to say sends ok
  1854. sendPossibleHandler =
  1855. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandler;
  1856. sendPossibleHandlerCtx =
  1857. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandlerCtx;
  1858. // Get the completion routines
  1859. if (pAdspConn->adspco_Flags &
  1860. (ADSPCO_ACCEPT_IRP | ADSPCO_LISTEN_IRP))
  1861. {
  1862. atalkAdspAddrDeQueueOpenReq(pAdspAddr,
  1863. pAdspConn->adspco_RemoteConnId,
  1864. &pAdspConn->adspco_RemoteAddr,
  1865. &pOpenReq);
  1866. pAdspConn->adspco_Flags &= ~(ADSPCO_ACCEPT_IRP |
  1867. ADSPCO_LISTEN_IRP);
  1868. completionRoutine = pAdspConn->adspco_ListenCompletion;
  1869. completionCtx = pAdspConn->adspco_ListenCtx;
  1870. }
  1871. else
  1872. {
  1873. ASSERT(pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_CONNECT);
  1874. completionRoutine = pAdspConn->adspco_ConnectCompletion;
  1875. completionCtx = pAdspConn->adspco_ConnectCtx;
  1876. }
  1877. // Start the probe and the retransmit timers
  1878. // Set the flags
  1879. pAdspConn->adspco_Flags |= (ADSPCO_CONN_TIMER | ADSPCO_RETRANSMIT_TIMER);
  1880. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 2, &error);
  1881. if (!ATALK_SUCCESS(error))
  1882. {
  1883. KeBugCheck(0);
  1884. }
  1885. AtalkTimerInitialize(&pAdspConn->adspco_ConnTimer,
  1886. atalkAdspConnMaintenanceTimer,
  1887. ADSP_PROBE_INTERVAL);
  1888. AtalkTimerScheduleEvent(&pAdspConn->adspco_ConnTimer);
  1889. AtalkTimerInitialize(&pAdspConn->adspco_RetransmitTimer,
  1890. atalkAdspRetransmitTimer,
  1891. ADSP_RETRANSMIT_INTERVAL);
  1892. AtalkTimerScheduleEvent(&pAdspConn->adspco_RetransmitTimer);
  1893. }
  1894. break;
  1895. default:
  1896. KeBugCheck(0);
  1897. break;
  1898. }
  1899. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  1900. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  1901. relAddrLock = FALSE;
  1902. // If a open request was dequeue free it now
  1903. if (pOpenReq != NULL)
  1904. {
  1905. AtalkFreeMemory(pOpenReq);
  1906. }
  1907. // Set last contact time. ConnMaintenanceTimer is in order of seconds.
  1908. pAdspConn->adspco_LastContactTime = AtalkGetCurrentTick();
  1909. if (controlCode == ADSP_OPENCONN_REQANDACK_CODE)
  1910. {
  1911. // If we received a req&ack
  1912. atalkAdspSendOpenControl(pAdspConn);
  1913. }
  1914. // Call connect routine
  1915. if (*completionRoutine != NULL)
  1916. {
  1917. (*completionRoutine)(error, completionCtx);
  1918. }
  1919. // Are sends ok?
  1920. if (*sendPossibleHandler != NULL)
  1921. {
  1922. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  1923. pAdspConn->adspco_ConnCtx,
  1924. atalkAdspMaxSendSize(pAdspConn));
  1925. }
  1926. if (openTimerCancelled)
  1927. {
  1928. AtalkAdspConnDereference(pAdspConn);
  1929. }
  1930. AtalkAdspConnDereference(pAdspConn);
  1931. }
  1932. #if DBG
  1933. else
  1934. {
  1935. ASSERT(0);
  1936. }
  1937. #endif
  1938. if (relAddrLock)
  1939. {
  1940. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  1941. }
  1942. }
  1943. LOCAL VOID
  1944. atalkAdspHandleAttn(
  1945. IN PADSP_CONNOBJ pAdspConn,
  1946. IN PBYTE pPkt,
  1947. IN USHORT PktLen,
  1948. IN PATALK_ADDR pSrcAddr,
  1949. IN ULONG RemoteAttnSendSeq,
  1950. IN ULONG RemoteAttnRecvSeq,
  1951. IN ULONG RemoteRecvWindow,
  1952. IN BYTE Descriptor
  1953. )
  1954. /*++
  1955. Routine Description:
  1956. Arguments:
  1957. Return Value:
  1958. --*/
  1959. {
  1960. BYTE controlCode;
  1961. KIRQL OldIrql;
  1962. PIRP exRecvIrp;
  1963. PTDI_IND_RECEIVE_EXPEDITED exRecvHandler;
  1964. PVOID exRecvHandlerCtx;
  1965. ULONG exIndicateFlags;
  1966. NTSTATUS ntStatus;
  1967. PBYTE exReadBuf;
  1968. ULONG bytesTaken;
  1969. USHORT exWriteBufLen;
  1970. PBYTE exWriteChBuf = NULL;
  1971. BOOLEAN freeBuf = FALSE,
  1972. timerCancelled = FALSE;
  1973. PAMDL exWriteBuf = NULL;
  1974. GENERIC_WRITE_COMPLETION exWriteCompletion = NULL;
  1975. PVOID exWriteCtx = NULL;
  1976. UNREFERENCED_PARAMETER(RemoteRecvWindow);
  1977. controlCode = (Descriptor & ADSP_CONTROL_MASK);
  1978. // Skip the adsp header
  1979. pPkt += ADSP_DATA_OFF;
  1980. PktLen -= ADSP_DATA_OFF;
  1981. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  1982. ("atalkAdspHandleAttn: PktLen %d\n", PktLen));
  1983. // Drop if we are not active! Pkt must atleast contain
  1984. // attention code if it is not a control packet.
  1985. if (((pAdspConn->adspco_Flags & ADSPCO_ACTIVE) == 0) ||
  1986. (controlCode != 0) ||
  1987. (((Descriptor & ADSP_CONTROL_FLAG) == 0) &&
  1988. (PktLen < ADSP_MIN_ATTEN_PKT_SIZE)))
  1989. {
  1990. return;
  1991. }
  1992. // Allocate if we have some data, ie. we are not just an ack.
  1993. if ((Descriptor & ADSP_CONTROL_FLAG) == 0)
  1994. {
  1995. if ((exReadBuf = AtalkAllocMemory(PktLen)) == NULL)
  1996. {
  1997. return;
  1998. }
  1999. freeBuf = TRUE;
  2000. // Copy the attention code from wire-to-host format
  2001. GETSHORT2SHORT((PUSHORT)exReadBuf, pPkt);
  2002. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2003. ("atalkAdspHandleAttn: Recd Attn Code %lx\n", *(PUSHORT)exReadBuf));
  2004. // Copy the rest of the data
  2005. RtlCopyMemory(exReadBuf + sizeof(USHORT),
  2006. pPkt + sizeof(USHORT),
  2007. PktLen - sizeof(USHORT));
  2008. }
  2009. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2010. do
  2011. {
  2012. if (RemoteAttnRecvSeq == (pAdspConn->adspco_SendAttnSeq + 1))
  2013. {
  2014. // This implies an ack of our last attention
  2015. pAdspConn->adspco_SendAttnSeq += 1;
  2016. // Check if we are waiting for an attention ack.
  2017. if (pAdspConn->adspco_Flags & ADSPCO_EXSEND_IN_PROGRESS)
  2018. {
  2019. exWriteCompletion = pAdspConn->adspco_ExWriteCompletion;
  2020. exWriteCtx = pAdspConn->adspco_ExWriteCtx;
  2021. exWriteBuf = pAdspConn->adspco_ExWriteBuf;
  2022. exWriteBufLen = pAdspConn->adspco_ExWriteBufLen;
  2023. exWriteChBuf = pAdspConn->adspco_ExWriteChBuf;
  2024. timerCancelled = AtalkTimerCancelEvent(&pAdspConn->adspco_ExRetryTimer,
  2025. NULL);
  2026. pAdspConn->adspco_Flags &= ~ADSPCO_EXSEND_IN_PROGRESS;
  2027. }
  2028. }
  2029. if (RemoteAttnSendSeq != pAdspConn->adspco_RecvAttnSeq)
  2030. {
  2031. break;
  2032. }
  2033. if (Descriptor & ADSP_CONTROL_FLAG)
  2034. {
  2035. // Ack only, no data to handle
  2036. break;
  2037. }
  2038. // Get the expedited receive handler.
  2039. exRecvHandler = pAdspConn->adspco_pAssocAddr->adspao_ExpRecvHandler;
  2040. exRecvHandlerCtx = pAdspConn->adspco_pAssocAddr->adspao_ExpRecvHandlerCtx;
  2041. if (((pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_RECD) == 0) &&
  2042. (*exRecvHandler != NULL))
  2043. {
  2044. exIndicateFlags = TDI_RECEIVE_EXPEDITED |
  2045. TDI_RECEIVE_PARTIAL;
  2046. pAdspConn->adspco_Flags |= ADSPCO_ATTN_DATA_RECD;
  2047. if (Descriptor & ADSP_EOM_FLAG)
  2048. {
  2049. exIndicateFlags &= ~TDI_RECEIVE_PARTIAL;
  2050. exIndicateFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
  2051. pAdspConn->adspco_Flags |= ADSPCO_ATTN_DATA_EOM;
  2052. }
  2053. pAdspConn->adspco_ExRecdData = exReadBuf;
  2054. pAdspConn->adspco_ExRecdLen = PktLen;
  2055. freeBuf = FALSE;
  2056. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2057. ("atalkAdspHandleAttn: Indicating exp data %ld\n", PktLen));
  2058. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2059. ntStatus = (*exRecvHandler)(exRecvHandlerCtx,
  2060. pAdspConn->adspco_ConnCtx,
  2061. exIndicateFlags,
  2062. PktLen,
  2063. PktLen,
  2064. &bytesTaken,
  2065. pPkt,
  2066. &exRecvIrp);
  2067. ASSERT((bytesTaken == 0) || (bytesTaken == PktLen));
  2068. if (ntStatus == STATUS_MORE_PROCESSING_REQUIRED)
  2069. {
  2070. if (exRecvIrp != NULL)
  2071. {
  2072. // Post the receive as if it came from the io system
  2073. ntStatus = AtalkDispatchInternalDeviceControl(
  2074. (PDEVICE_OBJECT)AtalkDeviceObject[ATALK_DEV_ADSP],
  2075. exRecvIrp);
  2076. ASSERT(ntStatus == STATUS_PENDING);
  2077. }
  2078. else
  2079. {
  2080. ASSERTMSG("atalkAdspReadComplete: No receive irp!\n", 0);
  2081. KeBugCheck(0);
  2082. }
  2083. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2084. }
  2085. else if (ntStatus == STATUS_SUCCESS)
  2086. {
  2087. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2088. if (bytesTaken != 0)
  2089. {
  2090. // Assume all of the data was read.
  2091. ASSERT(bytesTaken == PktLen);
  2092. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2093. ("atalkAdspHandleAttn: All bytes read %lx\n", bytesTaken));
  2094. // Attention has been accepted, we need to ack it.
  2095. // Since spinlock was released, recheck flag.
  2096. if (pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_RECD)
  2097. {
  2098. pAdspConn->adspco_Flags &= ~(ADSPCO_ATTN_DATA_RECD |
  2099. ADSPCO_ATTN_DATA_EOM);
  2100. freeBuf = TRUE;
  2101. }
  2102. // Send ack for the attention
  2103. atalkAdspSendControl(pAdspConn,
  2104. ADSP_CONTROL_FLAG + ADSP_ATTEN_FLAG);
  2105. }
  2106. }
  2107. else if (ntStatus == STATUS_DATA_NOT_ACCEPTED)
  2108. {
  2109. // Client may have posted a receive in the indication. Or
  2110. // it will post a receive later on. Do nothing here.
  2111. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2112. ("atalkAdspHandleAttn: Indication status %lx\n", ntStatus));
  2113. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2114. }
  2115. }
  2116. if (pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_RECD)
  2117. {
  2118. atalkAdspRecvAttn(pAdspConn);
  2119. }
  2120. } while (FALSE);
  2121. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2122. if (*exWriteCompletion != NULL)
  2123. {
  2124. if (exWriteChBuf != NULL)
  2125. {
  2126. AtalkFreeMemory(exWriteChBuf);
  2127. }
  2128. (*exWriteCompletion)(ATALK_NO_ERROR,
  2129. exWriteBuf,
  2130. exWriteBufLen,
  2131. exWriteCtx);
  2132. }
  2133. if (timerCancelled)
  2134. {
  2135. AtalkAdspConnDereference(pAdspConn);
  2136. }
  2137. if (freeBuf)
  2138. {
  2139. ASSERT(exReadBuf != NULL);
  2140. AtalkFreeMemory(exReadBuf);
  2141. }
  2142. }
  2143. LOCAL VOID
  2144. atalkAdspHandlePiggyBackAck(
  2145. IN PADSP_CONNOBJ pAdspConn,
  2146. IN ULONG RemoteNextRecvSeq,
  2147. IN ULONG RemoteRecvWindow
  2148. )
  2149. /*++
  2150. Routine Description:
  2151. Arguments:
  2152. Return Value:
  2153. --*/
  2154. {
  2155. ULONG newSendWindowSeq, sendSize, windowSize;
  2156. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  2157. KIRQL OldIrql;
  2158. PVOID sendPossibleHandlerCtx;
  2159. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2160. ("atalkAdspHandlePiggyBackAck: Recd ack %lx - %lx.%lx\n",
  2161. pAdspConn, RemoteNextRecvSeq, RemoteRecvWindow));
  2162. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2163. if (UNSIGNED_BETWEEN_WITH_WRAP(pAdspConn->adspco_FirstRtmtSeq,
  2164. pAdspConn->adspco_SendSeq,
  2165. RemoteNextRecvSeq))
  2166. {
  2167. ULONG size;
  2168. // Discard acked data from the send queue
  2169. size = (ULONG)(RemoteNextRecvSeq - pAdspConn->adspco_FirstRtmtSeq);
  2170. pAdspConn->adspco_FirstRtmtSeq = RemoteNextRecvSeq;
  2171. atalkAdspDiscardFromBufferQueue(&pAdspConn->adspco_SendQueue,
  2172. size,
  2173. &pAdspConn->adspco_NextSendQueue,
  2174. ATALK_NO_ERROR,
  2175. pAdspConn);
  2176. }
  2177. // We almost always can use the header values to update the
  2178. // sendwindowseqnum
  2179. newSendWindowSeq = RemoteNextRecvSeq +
  2180. (ULONG)RemoteRecvWindow -
  2181. (ULONG)1;
  2182. if (UNSIGNED_GREATER_WITH_WRAP(newSendWindowSeq,
  2183. pAdspConn->adspco_SendWindowSeq))
  2184. {
  2185. pAdspConn->adspco_SendWindowSeq = newSendWindowSeq;
  2186. }
  2187. if (!IsListEmpty(&pAdspConn->adspco_PendedSends))
  2188. {
  2189. AtalkAdspProcessQueuedSend(pAdspConn);
  2190. }
  2191. sendPossibleHandler =
  2192. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandler;
  2193. sendPossibleHandlerCtx =
  2194. pAdspConn->adspco_pAssocAddr->adspao_SendPossibleHandlerCtx;
  2195. // Call sendok handler for the size of the connection if non-zero
  2196. windowSize = (LONG)(pAdspConn->adspco_SendWindowSeq -
  2197. pAdspConn->adspco_SendSeq +
  2198. (LONG)1);
  2199. sendSize = MIN(atalkAdspMaxSendSize(pAdspConn), windowSize);
  2200. if ((sendSize != 0) &&
  2201. IsListEmpty(&pAdspConn->adspco_PendedSends) &&
  2202. (pAdspConn->adspco_Flags & ADSPCO_SEND_WINDOW_CLOSED) &&
  2203. (*sendPossibleHandler != NULL))
  2204. {
  2205. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  2206. pAdspConn->adspco_ConnCtx,
  2207. sendSize);
  2208. pAdspConn->adspco_Flags &= ~ADSPCO_SEND_WINDOW_CLOSED;
  2209. }
  2210. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2211. }
  2212. LOCAL VOID
  2213. atalkAdspHandleControl(
  2214. IN PADSP_CONNOBJ pAdspConn,
  2215. IN PBYTE pPkt,
  2216. IN USHORT PktLen,
  2217. IN PATALK_ADDR pSrcAddr,
  2218. IN ULONG RemoteFirstByteSeq,
  2219. IN ULONG RemoteNextRecvSeq,
  2220. IN ULONG RemoteRecvWindow,
  2221. IN BYTE Descriptor
  2222. )
  2223. /*++
  2224. Routine Description:
  2225. Arguments:
  2226. Return Value:
  2227. --*/
  2228. {
  2229. BYTE controlCode;
  2230. KIRQL OldIrql;
  2231. ATALK_ERROR Error;
  2232. // The ack request flag can be set in any control packet. Send
  2233. // an immediately. We will also send any data if possible.
  2234. if (Descriptor & ADSP_ACK_REQ_FLAG)
  2235. {
  2236. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2237. ("atalkAdspHandleControl: Recd ackreq for %lx\n", pAdspConn));
  2238. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2239. atalkAdspSendData(pAdspConn);
  2240. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2241. }
  2242. controlCode = (Descriptor & ADSP_CONTROL_MASK);
  2243. switch (controlCode)
  2244. {
  2245. case ADSP_PROBE_OR_ACK_CODE:
  2246. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2247. ("atalkAdspHandleControl: Recd probe for %lx\n", pAdspConn));
  2248. // A PROBE has its ACKRequest flag set, so we would have handled
  2249. // that above. Also, we've already set the lastContactTime in the
  2250. // packet in routine. So if this is an ack we've handled it.
  2251. // Check to see if some data was acked and if we have data to send.
  2252. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2253. if (!(Descriptor & ADSP_ACK_REQ_FLAG) &&
  2254. (atalkAdspBufferQueueSize(&pAdspConn->adspco_NextSendQueue) != 0) &&
  2255. (pAdspConn->adspco_SendSeq != (pAdspConn->adspco_SendWindowSeq + 1)))
  2256. {
  2257. atalkAdspSendData(pAdspConn);
  2258. }
  2259. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2260. break;
  2261. case ADSP_CLOSE_CONN_CODE:
  2262. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2263. ("atalkAdspHandleControl: Recd CLOSE for %lx\n", pAdspConn));
  2264. AtalkAdspConnReferenceByPtr(pAdspConn, &Error);
  2265. if (ATALK_SUCCESS(Error))
  2266. {
  2267. AtalkTimerScheduleEvent(&pAdspConn->adspco_DisconnectTimer);
  2268. }
  2269. else
  2270. {
  2271. AtalkAdspDisconnect(pAdspConn,
  2272. ATALK_REMOTE_DISCONNECT,
  2273. NULL,
  2274. NULL);
  2275. }
  2276. break;
  2277. case ADSP_FORWARD_RESET_CODE:
  2278. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  2279. ("atalkAdspHandleControl: Recd FWDRESET for %lx\n", pAdspConn));
  2280. pAdspConn->adspco_Flags |= ADSPCO_FORWARD_RESET_RECD;
  2281. AtalkAdspDisconnect(pAdspConn,
  2282. ATALK_LOCAL_DISCONNECT,
  2283. NULL,
  2284. NULL);
  2285. break;
  2286. case ADSP_FORWARD_RESETACK_CODE:
  2287. // We never send forward resets (interface not exposed), so
  2288. // we should never be getting these. Drop if we do.
  2289. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  2290. ("atalkAdspHandleControl: Recd ForwardReset ACK!!\n"));
  2291. break;
  2292. case ADSP_RETRANSMIT_CODE:
  2293. // Any acks should have been processed by now. Back up and
  2294. // do a retransmit by rewinding sequence number.
  2295. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2296. if (UNSIGNED_BETWEEN_WITH_WRAP(pAdspConn->adspco_FirstRtmtSeq,
  2297. pAdspConn->adspco_SendSeq,
  2298. RemoteNextRecvSeq))
  2299. {
  2300. pAdspConn->adspco_SendSeq = pAdspConn->adspco_FirstRtmtSeq;
  2301. pAdspConn->adspco_NextSendQueue = pAdspConn->adspco_SendQueue;
  2302. atalkAdspSendData(pAdspConn);
  2303. }
  2304. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2305. break;
  2306. default:
  2307. break;
  2308. }
  2309. }
  2310. LOCAL VOID
  2311. atalkAdspHandleData(
  2312. IN PADSP_CONNOBJ pAdspConn,
  2313. IN PBYTE pPkt,
  2314. IN USHORT PktLen,
  2315. IN PATALK_ADDR pSrcAddr,
  2316. IN ULONG RemoteFirstByteSeq,
  2317. IN ULONG RemoteNextRecvSeq,
  2318. IN ULONG RemoteRecvWindow,
  2319. IN BYTE Descriptor
  2320. )
  2321. /*++
  2322. Routine Description:
  2323. Arguments:
  2324. Return Value:
  2325. --*/
  2326. {
  2327. BOOLEAN eom, tdiEom;
  2328. PBUFFER_CHUNK pBufferChunk;
  2329. KIRQL OldIrql;
  2330. ULONG dataSize;
  2331. BOOLEAN freeChunk = FALSE,
  2332. sendAck = (Descriptor & ADSP_ACK_REQ_FLAG);
  2333. eom = (Descriptor & ADSP_EOM_FLAG) ? TRUE : FALSE;
  2334. dataSize = PktLen - ADSP_DATA_OFF;
  2335. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2336. do
  2337. {
  2338. // Drop if we are not active! And if there is no data
  2339. if ((pAdspConn->adspco_Flags & ADSPCO_ACTIVE) == 0)
  2340. {
  2341. sendAck = FALSE;
  2342. break;
  2343. }
  2344. tdiEom = (eom && (pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_MESSAGE));
  2345. // We can only access addr object when active.
  2346. if ((dataSize == 0) && !tdiEom)
  2347. {
  2348. // Increment seqnumbers and we have consumed this packet.
  2349. pAdspConn->adspco_RecvSeq += (ULONG)(BYTECOUNT(eom));
  2350. pAdspConn->adspco_RecvWindow -= (LONG)(BYTECOUNT(eom));
  2351. break;
  2352. }
  2353. // Preallocate the buffer chunk
  2354. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2355. ("Recd Data %d Eom %d\n", dataSize, eom));
  2356. pBufferChunk = atalkAdspAllocCopyChunk(pPkt + ADSP_DATA_OFF,
  2357. (USHORT)dataSize,
  2358. tdiEom,
  2359. TRUE);
  2360. if (pBufferChunk == NULL)
  2361. break;
  2362. freeChunk = TRUE;
  2363. if (RemoteFirstByteSeq != pAdspConn->adspco_RecvSeq)
  2364. {
  2365. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  2366. ("atalkAdspHandleData: Dropping out of sequence adsp packet\n"));
  2367. if ((pAdspConn->adspco_OutOfSeqCount += 1) >= ADSP_OUT_OF_SEQ_PACKETS_MAX)
  2368. {
  2369. atalkAdspSendControl(pAdspConn,
  2370. ADSP_CONTROL_FLAG + ADSP_RETRANSMIT_CODE);
  2371. pAdspConn->adspco_OutOfSeqCount = 0;
  2372. }
  2373. break;
  2374. }
  2375. // Handle a > receive window packet
  2376. if ((dataSize + BYTECOUNT(eom)) > (ULONG)pAdspConn->adspco_RecvWindow)
  2377. {
  2378. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2379. ("atalkAdspHandleData: Recd > window data %d.%ld\n",
  2380. dataSize, pAdspConn->adspco_RecvWindow));
  2381. break;
  2382. }
  2383. // Accept the data
  2384. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2385. ("atalkAdspHandleData: accepting data adsp packet %d\n", dataSize));
  2386. atalkAdspAddToBufferQueue(&pAdspConn->adspco_RecvQueue,
  2387. pBufferChunk,
  2388. NULL);
  2389. // Put it in the queue successfully
  2390. freeChunk = FALSE;
  2391. // Update the receive sequence numbers
  2392. pAdspConn->adspco_RecvSeq += (ULONG)(dataSize + BYTECOUNT(eom));
  2393. pAdspConn->adspco_RecvWindow -= (LONG)(dataSize + BYTECOUNT(eom));
  2394. // The receive windows should never go below zero! If it does, we could have
  2395. // memory overruns.
  2396. ASSERT(pAdspConn->adspco_RecvWindow >= 0);
  2397. if (pAdspConn->adspco_RecvWindow < 0)
  2398. {
  2399. KeBugCheck(0);
  2400. }
  2401. // Do indications/handle pending receives etc.
  2402. atalkAdspRecvData(pAdspConn);
  2403. } while (FALSE);
  2404. // ACK if requested, and send any data at the same time too.
  2405. if (sendAck)
  2406. {
  2407. atalkAdspSendData(pAdspConn);
  2408. }
  2409. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2410. if (freeChunk)
  2411. {
  2412. ASSERT(pBufferChunk != NULL);
  2413. AtalkFreeMemory(pBufferChunk);
  2414. }
  2415. }
  2416. //
  2417. // ADSP SUPPORT ROUTINES
  2418. //
  2419. #define SLS_OPEN_CONN_REF 0x0008
  2420. #define SLS_ACCEPT_IRP 0x0010
  2421. #define SLS_CONN_TIMER_REF 0x0040
  2422. #define SLS_LISTEN_DEQUEUED 0x0080
  2423. LOCAL VOID
  2424. atalkAdspHandleOpenReq(
  2425. IN PADSP_ADDROBJ pAdspAddr,
  2426. IN PBYTE pPkt,
  2427. IN USHORT PktLen,
  2428. IN PATALK_ADDR pSrcAddr,
  2429. IN USHORT RemoteConnId,
  2430. IN ULONG RemoteFirstByteSeq,
  2431. IN ULONG RemoteNextRecvSeq,
  2432. IN ULONG RemoteRecvWindow,
  2433. IN BYTE Descriptor
  2434. )
  2435. /*++
  2436. Routine Description:
  2437. Arguments:
  2438. Return Value:
  2439. --*/
  2440. {
  2441. PADSP_CONNOBJ pAdspConn;
  2442. PTDI_IND_SEND_POSSIBLE sendPossibleHandler;
  2443. PVOID sendPossibleHandlerCtx;
  2444. USHORT adspVersionStamp, destConnId, localConnId;
  2445. ULONG recvAttnSeq;
  2446. ULONG index;
  2447. BOOLEAN DerefConn = FALSE;
  2448. PADSP_OPEN_REQ pOpenReq = NULL;
  2449. USHORT openResr = 0;
  2450. KIRQL OldIrql;
  2451. ATALK_ERROR error = ATALK_NO_ERROR;
  2452. // Are there any listening connections? Or do we have a
  2453. // set handler?
  2454. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  2455. do
  2456. {
  2457. // Get the other information from the adsp header
  2458. GETSHORT2SHORT(&adspVersionStamp, pPkt + ADSP_VERSION_STAMP_OFF);
  2459. GETSHORT2SHORT(&destConnId, pPkt + ADSP_DEST_CONNID_OFF);
  2460. GETDWORD2DWORD(&recvAttnSeq, pPkt + ADSP_NEXT_ATTEN_SEQNUM_OFF);
  2461. // Drop request if version isnt right.
  2462. if (adspVersionStamp != ADSP_VERSION)
  2463. {
  2464. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  2465. ("atalkAdspPacketIn: Version incorrect\n"));
  2466. error = ATALK_INVALID_REQUEST;
  2467. break;
  2468. }
  2469. // Is this a duplicate request - same remote address/id?
  2470. if (atalkAdspIsDuplicateOpenReq(pAdspAddr,
  2471. RemoteConnId,
  2472. pSrcAddr))
  2473. {
  2474. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  2475. ("atalkAdspPacketIn: Duplicate open req\n"));
  2476. error = ATALK_INVALID_REQUEST;
  2477. break;
  2478. }
  2479. // Allocate the open request structure. Do it here to avoid
  2480. // sending in a whole lot of parameters.
  2481. if ((pOpenReq = (PADSP_OPEN_REQ)AtalkAllocMemory(sizeof(ADSP_OPEN_REQ))) == NULL)
  2482. {
  2483. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  2484. ("atalkAdspPacketIn: Could not alloc\n"));
  2485. error = ATALK_RESR_MEM;
  2486. RES_LOG_ERROR();
  2487. break;
  2488. }
  2489. // Initialize the structure. This will be queued into the address
  2490. // object by listenindicate if successful.
  2491. pOpenReq->or_Next = NULL;
  2492. pOpenReq->or_RemoteAddr = *pSrcAddr;
  2493. pOpenReq->or_RemoteConnId = RemoteConnId;
  2494. pOpenReq->or_FirstByteSeq = RemoteFirstByteSeq;
  2495. pOpenReq->or_NextRecvSeq = RemoteNextRecvSeq;
  2496. pOpenReq->or_RecvWindow = RemoteRecvWindow;
  2497. localConnId = atalkAdspGetNextConnId(pAdspAddr, &error);
  2498. ASSERT(ATALK_SUCCESS(error));
  2499. if (ATALK_SUCCESS(error))
  2500. {
  2501. atalkAdspListenIndicateNonInterlock(pAdspAddr,
  2502. pOpenReq,
  2503. &pAdspConn,
  2504. &error);
  2505. }
  2506. } while (FALSE);
  2507. // If either the indication or listen didnt happen well,
  2508. // break out of the main while loop.
  2509. if (!ATALK_SUCCESS(error))
  2510. {
  2511. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  2512. if (pOpenReq != NULL)
  2513. {
  2514. AtalkFreeMemory(pOpenReq);
  2515. }
  2516. return;
  2517. }
  2518. ASSERT(ATALK_SUCCESS(error));
  2519. // Common for both listen and indicate. The connection object
  2520. // should be referenced.
  2521. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2522. ("atalkAdspOpenReq: ConnId %lx Rem %lx.%lx.%lx\n",
  2523. pOpenReq->or_RemoteConnId,
  2524. pOpenReq->or_RemoteAddr.ata_Network,
  2525. pOpenReq->or_RemoteAddr.ata_Node,
  2526. pOpenReq->or_RemoteAddr.ata_Socket));
  2527. // Thread the connection object into addr lookup by session id.
  2528. index = HASH_ID_SRCADDR(pOpenReq->or_RemoteConnId,
  2529. &pOpenReq->or_RemoteAddr);
  2530. index %= ADSP_CONN_HASH_SIZE;
  2531. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  2532. pAdspConn->adspco_Flags &= ~ADSPCO_LISTENING;
  2533. pAdspConn->adspco_Flags |= (ADSPCO_HALF_ACTIVE |
  2534. ADSPCO_SEEN_REMOTE_OPEN |
  2535. ADSPCO_OPEN_TIMER);
  2536. pAdspConn->adspco_ConnectAttempts = ADSP_MAX_OPEN_ATTEMPTS;
  2537. // Store the information in the connection structure given by
  2538. // the connection object thats passed back in the indication
  2539. // or is part of the listen structure.
  2540. pAdspConn->adspco_RecvWindow=
  2541. pAdspConn->adspco_SendQueueMax =
  2542. pAdspConn->adspco_RecvQueueMax = ADSP_DEF_SEND_RX_WINDOW_SIZE;
  2543. // Store the remote information
  2544. pAdspConn->adspco_RemoteAddr = pOpenReq->or_RemoteAddr;
  2545. pAdspConn->adspco_RemoteConnId = pOpenReq->or_RemoteConnId;
  2546. pAdspConn->adspco_LocalConnId = localConnId;
  2547. pAdspConn->adspco_SendSeq = pOpenReq->or_FirstByteSeq;
  2548. pAdspConn->adspco_FirstRtmtSeq = pOpenReq->or_NextRecvSeq;
  2549. pAdspConn->adspco_SendWindowSeq = pOpenReq->or_NextRecvSeq +
  2550. pOpenReq->or_RecvWindow - 1;
  2551. pAdspConn->adspco_RecvAttnSeq = recvAttnSeq;
  2552. pAdspConn->adspco_pNextActive = pAdspAddr->adspao_pActiveHash[index];
  2553. pAdspAddr->adspao_pActiveHash[index] = pAdspConn;
  2554. // Remember the ddp socket.
  2555. pAdspConn->adspco_pDdpAddr = pAdspAddr->adspao_pDdpAddr;
  2556. // Initialize pended sends list
  2557. InitializeListHead(&pAdspConn->adspco_PendedSends);
  2558. // Call the send data event handler on the associated address with
  2559. // 0 to turn off selects on writes. We do this before we complete the
  2560. // accept.
  2561. sendPossibleHandler = pAdspAddr->adspao_SendPossibleHandler;
  2562. sendPossibleHandlerCtx = pAdspAddr->adspao_SendPossibleHandlerCtx;
  2563. // Start open timer. Reference is the reference
  2564. // at the beginning.
  2565. AtalkTimerInitialize(&pAdspConn->adspco_OpenTimer,
  2566. atalkAdspOpenTimer,
  2567. ADSP_OPEN_INTERVAL);
  2568. AtalkTimerScheduleEvent(&pAdspConn->adspco_OpenTimer);
  2569. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  2570. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  2571. // Connection is all set up, send ack to remote and wait
  2572. // for its ack before switching state to active.
  2573. if (*sendPossibleHandler != NULL)
  2574. {
  2575. (*sendPossibleHandler)(sendPossibleHandlerCtx,
  2576. pAdspConn->adspco_ConnCtx,
  2577. 0);
  2578. }
  2579. // Send the open control.
  2580. atalkAdspSendOpenControl(pAdspConn);
  2581. // Remove the reference on the connection added during
  2582. // indicate/listen if we did not start the open timer.
  2583. if (DerefConn)
  2584. {
  2585. AtalkAdspConnDereference(pAdspConn);
  2586. }
  2587. }
  2588. LOCAL VOID
  2589. atalkAdspListenIndicateNonInterlock(
  2590. IN PADSP_ADDROBJ pAdspAddr,
  2591. IN PADSP_OPEN_REQ pOpenReq,
  2592. IN PADSP_CONNOBJ * ppAdspConn,
  2593. IN PATALK_ERROR pError
  2594. )
  2595. /*++
  2596. Routine Description:
  2597. Arguments:
  2598. Return Value:
  2599. --*/
  2600. {
  2601. ATALK_ERROR error;
  2602. TA_APPLETALK_ADDRESS tdiAddr;
  2603. PTDI_IND_CONNECT indicationRoutine;
  2604. PVOID indicationCtx;
  2605. NTSTATUS status;
  2606. CONNECTION_CONTEXT ConnCtx;
  2607. PIRP acceptIrp;
  2608. PADSP_CONNOBJ pAdspConn;
  2609. ATALK_ADDR remoteAddr;
  2610. USHORT remoteConnId;
  2611. BOOLEAN indicate = TRUE;
  2612. // If no listens posted, no handler, drop the request.
  2613. error = ATALK_RESR_MEM;
  2614. // Queue in the open request to the address. Cant release the
  2615. // addrlock without doing this.
  2616. pOpenReq->or_Next = pAdspAddr->adspao_OpenReq;
  2617. pAdspAddr->adspao_OpenReq = pOpenReq;
  2618. pAdspConn = pAdspAddr->adspao_pListenConn;
  2619. remoteAddr = pOpenReq->or_RemoteAddr;
  2620. remoteConnId = pOpenReq->or_RemoteConnId;
  2621. if (pAdspConn != NULL)
  2622. {
  2623. ASSERT(VALID_ADSPCO(pAdspConn));
  2624. indicate = FALSE;
  2625. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  2626. // Ok, now its possible the connection object is already
  2627. // disconnecting/closing. Check for that, if so,
  2628. // drop this request
  2629. if (pAdspConn->adspco_Flags & ( ADSPCO_CLOSING |
  2630. ADSPCO_STOPPING |
  2631. ADSPCO_DISCONNECTING))
  2632. {
  2633. // dequeue open request, still first in list.
  2634. pAdspAddr->adspao_OpenReq = pAdspAddr->adspao_OpenReq->or_Next;
  2635. *pError = ATALK_INVALID_CONNECTION;
  2636. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  2637. return;
  2638. }
  2639. // There a connection with a pending listen. use it.
  2640. pAdspAddr->adspao_pListenConn = pAdspConn->adspco_pNextListen;
  2641. // Reference the connection object with a listen posted on it.
  2642. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 1, &error);
  2643. if (!ATALK_SUCCESS(error))
  2644. {
  2645. KeBugCheck(0);
  2646. }
  2647. // The listen request will also be completed when the
  2648. // ack is received.
  2649. pAdspConn->adspco_Flags |= ADSPCO_LISTEN_IRP;
  2650. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  2651. }
  2652. else if ((indicationRoutine = pAdspAddr->adspao_ConnHandler) != NULL)
  2653. {
  2654. indicationCtx = pAdspAddr->adspao_ConnHandlerCtx;
  2655. // Convert remote atalk address to tdi address
  2656. ATALKADDR_TO_TDI(&tdiAddr, &pOpenReq->or_RemoteAddr);
  2657. #if DBG
  2658. (&pAdspAddr->adspao_Lock)->FileLineLock |= 0x80000000;
  2659. #endif
  2660. RELEASE_SPIN_LOCK_DPC(&pAdspAddr->adspao_Lock);
  2661. status = (*indicationRoutine)(indicationCtx,
  2662. sizeof(tdiAddr),
  2663. (PVOID)&tdiAddr,
  2664. 0, // User data length
  2665. NULL, // User data
  2666. 0, // Option length
  2667. NULL, // Options
  2668. &ConnCtx,
  2669. &acceptIrp);
  2670. ACQUIRE_SPIN_LOCK_DPC(&pAdspAddr->adspao_Lock);
  2671. #if DBG
  2672. (&pAdspAddr->adspao_Lock)->FileLineLock &= ~0x80000000;
  2673. #endif
  2674. ASSERT(acceptIrp != NULL);
  2675. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2676. ("atalkAdspSlsHandler: indicate status %lx\n", status));
  2677. error = ATALK_RESR_MEM;
  2678. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2679. {
  2680. // Find the connection and accept the connection using that
  2681. // connection object.
  2682. AtalkAdspConnReferenceByCtxNonInterlock(pAdspAddr,
  2683. ConnCtx,
  2684. &pAdspConn,
  2685. &error);
  2686. if (!ATALK_SUCCESS(error))
  2687. {
  2688. // The connection object is closing, or is not found
  2689. // in our list. The accept irp must have had the same
  2690. // connection object. AFD isnt behaving well.
  2691. KeBugCheck(0);
  2692. }
  2693. if (acceptIrp != NULL)
  2694. {
  2695. // AFD re-uses connection objects. Make sure ths one is in
  2696. // the right state
  2697. pAdspConn->adspco_Flags &= ~(ADSPCO_LISTENING |
  2698. ADSPCO_CONNECTING |
  2699. ADSPCO_ACCEPT_IRP |
  2700. ADSPCO_LISTEN_IRP |
  2701. ADSPCO_ACTIVE |
  2702. ADSPCO_HALF_ACTIVE |
  2703. ADSPCO_SEEN_REMOTE_OPEN |
  2704. ADSPCO_DISCONNECTING |
  2705. ADSPCO_REMOTE_CLOSE |
  2706. ADSPCO_SEND_IN_PROGRESS |
  2707. ADSPCO_SEND_DENY |
  2708. ADSPCO_SEND_OPENACK |
  2709. ADSPCO_SEND_WINDOW_CLOSED |
  2710. ADSPCO_READ_PENDING |
  2711. ADSPCO_EXREAD_PENDING |
  2712. ADSPCO_FORWARD_RESET_RECD |
  2713. ADSPCO_ATTN_DATA_RECD |
  2714. ADSPCO_ATTN_DATA_EOM |
  2715. ADSPCO_EXSEND_IN_PROGRESS |
  2716. ADSPCO_OPEN_TIMER |
  2717. ADSPCO_RETRANSMIT_TIMER |
  2718. ADSPCO_CONN_TIMER);
  2719. pAdspConn->adspco_ListenCompletion = atalkAdspGenericComplete;
  2720. pAdspConn->adspco_ListenCtx = (PVOID)acceptIrp;
  2721. // This will be completed when we receive an ack
  2722. // for the open from the remote, i.e. both ends of the
  2723. // connection are open.
  2724. pAdspConn->adspco_Flags |= ADSPCO_ACCEPT_IRP;
  2725. }
  2726. }
  2727. }
  2728. if (ATALK_SUCCESS(*pError = error))
  2729. {
  2730. *ppAdspConn = pAdspConn;
  2731. }
  2732. else
  2733. {
  2734. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  2735. ("atalkAdspListenIndicateNonInterlock: No listen %lx\n", status));
  2736. if (indicate)
  2737. {
  2738. // Dequeue the open request.
  2739. atalkAdspAddrDeQueueOpenReq(pAdspAddr,
  2740. remoteConnId,
  2741. &remoteAddr,
  2742. &pOpenReq);
  2743. }
  2744. #if DBG
  2745. (&pAdspAddr->adspao_Lock)->FileLineLock |= 0x80000000;
  2746. #endif
  2747. RELEASE_SPIN_LOCK_DPC(&pAdspAddr->adspao_Lock);
  2748. atalkAdspSendDeny(pAdspAddr,
  2749. &remoteAddr,
  2750. remoteConnId);
  2751. ACQUIRE_SPIN_LOCK_DPC(&pAdspAddr->adspao_Lock);
  2752. #if DBG
  2753. (&pAdspAddr->adspao_Lock)->FileLineLock &= ~0x80000000;
  2754. #endif
  2755. }
  2756. }
  2757. ATALK_ERROR
  2758. atalkAdspSendExpedited(
  2759. IN PADSP_CONNOBJ pAdspConn,
  2760. IN PAMDL pWriteBuf,
  2761. IN USHORT WriteBufLen,
  2762. IN ULONG SendFlags,
  2763. IN PVOID pWriteCtx,
  2764. IN GENERIC_WRITE_COMPLETION CompletionRoutine
  2765. )
  2766. /*++
  2767. Routine Description:
  2768. Arguments:
  2769. The first two bytes of the writebuffer will contain the ushort
  2770. attention code. We need to put this back in the on-the-wire format
  2771. before sending it out.
  2772. Return Value:
  2773. --*/
  2774. {
  2775. ATALK_ERROR error;
  2776. KIRQL OldIrql;
  2777. PBYTE pExWriteChBuf;
  2778. USHORT attnCode;
  2779. NTSTATUS status;
  2780. ULONG bytesCopied;
  2781. BOOLEAN DerefConn = FALSE;
  2782. if ((WriteBufLen < ADSP_MIN_ATTEN_PKT_SIZE) ||
  2783. (WriteBufLen > ADSP_MAX_ATTEN_PKT_SIZE))
  2784. {
  2785. return ATALK_BUFFER_TOO_SMALL;
  2786. }
  2787. if ((pExWriteChBuf = AtalkAllocMemory(WriteBufLen)) == NULL)
  2788. {
  2789. return ATALK_RESR_MEM;
  2790. }
  2791. status = TdiCopyMdlToBuffer((PMDL)pWriteBuf,
  2792. 0,
  2793. pExWriteChBuf,
  2794. 0,
  2795. WriteBufLen,
  2796. &bytesCopied);
  2797. ASSERT(!NT_ERROR(status) && (bytesCopied == (ULONG)WriteBufLen));
  2798. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2799. do
  2800. {
  2801. if (((pAdspConn->adspco_Flags & ADSPCO_ACTIVE) == 0) ||
  2802. ((pAdspConn->adspco_Flags & (ADSPCO_CLOSING |
  2803. ADSPCO_STOPPING|
  2804. ADSPCO_DISCONNECTING))))
  2805. {
  2806. error = ATALK_ADSP_CONN_NOT_ACTIVE;
  2807. break;
  2808. }
  2809. if (pAdspConn->adspco_Flags & ADSPCO_EXSEND_IN_PROGRESS)
  2810. {
  2811. if (SendFlags & TDI_SEND_NON_BLOCKING)
  2812. {
  2813. // !!!NOTE!!!
  2814. // To avoid the race condition in AFD where an incoming
  2815. // send data indication setting send's possible to true
  2816. // is overwritten by this read's unwinding and setting it
  2817. // to false, we return ATALK_REQUEST_NOT_ACCEPTED, which
  2818. // will map to STATUS_REQUEST_NOT_ACCEPTED and then to
  2819. // WSAEWOULDBLOCK.
  2820. // error = ATALK_DEVICE_NOT_READY;
  2821. error = ATALK_REQUEST_NOT_ACCEPTED;
  2822. }
  2823. else
  2824. {
  2825. error = ATALK_TOO_MANY_COMMANDS;
  2826. }
  2827. break;
  2828. }
  2829. // Verify the attention code, this will a ushort in the first
  2830. // two bytes of the buffer, in host format.
  2831. attnCode = *(PUSHORT)pExWriteChBuf;
  2832. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  2833. ("atalkAdspSendExpedited: attnCode %lx\n", attnCode));
  2834. if ((attnCode < ADSP_MIN_ATTENCODE) ||
  2835. (attnCode > ADSP_MAX_ATTENCODE))
  2836. {
  2837. error = ATALK_INVALID_PARAMETER;
  2838. break;
  2839. }
  2840. // Put it back in machine format
  2841. PUTSHORT2SHORT(pExWriteChBuf, attnCode);
  2842. // Try to reference for the attention retransmit timer
  2843. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 1, &error);
  2844. if (!ATALK_SUCCESS(error))
  2845. {
  2846. break;
  2847. }
  2848. DerefConn = TRUE;
  2849. // Remember all the information in the connection object
  2850. pAdspConn->adspco_ExWriteFlags = SendFlags;
  2851. pAdspConn->adspco_ExWriteBuf = pWriteBuf;
  2852. pAdspConn->adspco_ExWriteBufLen = WriteBufLen;
  2853. pAdspConn->adspco_ExWriteCompletion = CompletionRoutine;
  2854. pAdspConn->adspco_ExWriteCtx = pWriteCtx;
  2855. pAdspConn->adspco_ExWriteChBuf = pExWriteChBuf;
  2856. pAdspConn->adspco_Flags |= ADSPCO_EXSEND_IN_PROGRESS;
  2857. // Start the retry timer
  2858. AtalkTimerInitialize(&pAdspConn->adspco_ExRetryTimer,
  2859. atalkAdspAttnRetransmitTimer,
  2860. ADSP_ATTENTION_INTERVAL);
  2861. AtalkTimerScheduleEvent(&pAdspConn->adspco_ExRetryTimer);
  2862. error = ATALK_PENDING;
  2863. } while (FALSE);
  2864. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2865. if (ATALK_SUCCESS(error))
  2866. {
  2867. atalkAdspSendAttn(pAdspConn);
  2868. error = ATALK_PENDING;
  2869. }
  2870. else
  2871. {
  2872. if (DerefConn)
  2873. {
  2874. AtalkAdspConnDereference(pAdspConn);
  2875. }
  2876. AtalkFreeMemory(pExWriteChBuf);
  2877. }
  2878. return error;
  2879. }
  2880. LOCAL VOID
  2881. atalkAdspSendOpenControl(
  2882. IN PADSP_CONNOBJ pAdspConn
  2883. )
  2884. /*++
  2885. Routine Description:
  2886. Arguments:
  2887. Return Value:
  2888. --*/
  2889. {
  2890. ATALK_ERROR error;
  2891. PBUFFER_DESC pBuffDesc;
  2892. BYTE descriptor;
  2893. KIRQL OldIrql;
  2894. BOOLEAN DerefConn = FALSE;
  2895. USHORT remoteConnId = 0;
  2896. SEND_COMPL_INFO SendInfo;
  2897. descriptor = ADSP_CONTROL_FLAG;
  2898. if (pAdspConn->adspco_Flags & ADSPCO_SEND_DENY)
  2899. {
  2900. descriptor += ADSP_OPENCONN_DENY_CODE;
  2901. remoteConnId = pAdspConn->adspco_RemoteConnId;
  2902. }
  2903. else if (pAdspConn->adspco_Flags & ADSPCO_ACTIVE)
  2904. {
  2905. descriptor += ADSP_OPENCONN_ACK_CODE;
  2906. remoteConnId = pAdspConn->adspco_RemoteConnId;
  2907. }
  2908. else if (pAdspConn->adspco_Flags & ADSPCO_SEEN_REMOTE_OPEN)
  2909. {
  2910. descriptor += ADSP_OPENCONN_REQANDACK_CODE;
  2911. remoteConnId = pAdspConn->adspco_RemoteConnId;
  2912. }
  2913. else
  2914. {
  2915. descriptor += ADSP_OPENCONN_REQ_CODE;
  2916. }
  2917. // Allocate the datagram buffer
  2918. pBuffDesc = AtalkAllocBuffDesc(NULL,
  2919. ADSP_NEXT_ATTEN_SEQNUM_OFF + sizeof(ULONG),
  2920. BD_CHAR_BUFFER | BD_FREE_BUFFER);
  2921. if (pBuffDesc == NULL)
  2922. {
  2923. DBGPRINT(DBG_COMP_RTMP, DBG_LEVEL_ERR,
  2924. ("AtalkAdspSendOpenControl: AtalkAllocBuffDesc failed\n"));
  2925. RES_LOG_ERROR();
  2926. return;
  2927. }
  2928. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  2929. // Try to reference connection for this call.
  2930. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 1, &error);
  2931. if (ATALK_SUCCESS(error))
  2932. {
  2933. DerefConn = TRUE;
  2934. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_SRC_CONNID_OFF,
  2935. pAdspConn->adspco_LocalConnId);
  2936. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_FIRST_BYTE_SEQNUM_OFF,
  2937. pAdspConn->adspco_SendSeq);
  2938. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_NEXT_RX_BYTESEQNUM_OFF,
  2939. pAdspConn->adspco_RecvSeq);
  2940. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_RX_WINDOW_SIZE_OFF,
  2941. pAdspConn->adspco_RecvWindow);
  2942. // Set the descriptor
  2943. pBuffDesc->bd_CharBuffer[ADSP_DESCRIPTOR_OFF] = descriptor;
  2944. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_VERSION_STAMP_OFF,
  2945. ADSP_VERSION);
  2946. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_DEST_CONNID_OFF,
  2947. remoteConnId);
  2948. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_NEXT_ATTEN_SEQNUM_OFF,
  2949. pAdspConn->adspco_RecvAttnSeq);
  2950. }
  2951. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  2952. if (ATALK_SUCCESS(error))
  2953. {
  2954. // We let the completion routine Deref the conn.
  2955. DerefConn = FALSE;
  2956. SendInfo.sc_TransmitCompletion = atalkAdspConnSendComplete;
  2957. SendInfo.sc_Ctx1 = pAdspConn;
  2958. SendInfo.sc_Ctx2 = pBuffDesc;
  2959. // SendInfo.sc_Ctx3 = NULL;
  2960. if(!ATALK_SUCCESS(AtalkDdpSend(pAdspConn->adspco_pDdpAddr,
  2961. &pAdspConn->adspco_RemoteAddr,
  2962. DDPPROTO_ADSP,
  2963. FALSE,
  2964. pBuffDesc,
  2965. NULL,
  2966. 0,
  2967. NULL,
  2968. &SendInfo)))
  2969. {
  2970. atalkAdspConnSendComplete(NDIS_STATUS_FAILURE, &SendInfo);
  2971. }
  2972. }
  2973. else
  2974. {
  2975. // Free the buffer descriptor
  2976. AtalkFreeBuffDesc(pBuffDesc);
  2977. }
  2978. if (DerefConn)
  2979. {
  2980. AtalkAdspConnDereference(pAdspConn);
  2981. }
  2982. }
  2983. LOCAL VOID
  2984. atalkAdspSendControl(
  2985. IN PADSP_CONNOBJ pAdspConn,
  2986. IN BYTE Descriptor
  2987. )
  2988. /*++
  2989. Routine Description:
  2990. Arguments:
  2991. Return Value:
  2992. --*/
  2993. {
  2994. ATALK_ERROR error;
  2995. PBUFFER_DESC pBuffDesc;
  2996. ULONG sendSeq, recvSeq, recvWindow;
  2997. BOOLEAN DerefConn = FALSE;
  2998. SEND_COMPL_INFO SendInfo;
  2999. // Try to reference connection for this call.
  3000. AtalkAdspConnReferenceByPtrNonInterlock(pAdspConn, 1, &error);
  3001. if (ATALK_SUCCESS(error))
  3002. {
  3003. DerefConn = TRUE;
  3004. if ((Descriptor & ADSP_ATTEN_FLAG) == 0)
  3005. {
  3006. sendSeq = pAdspConn->adspco_SendSeq;
  3007. recvSeq = pAdspConn->adspco_RecvSeq;
  3008. recvWindow = pAdspConn->adspco_RecvWindow;
  3009. }
  3010. else
  3011. {
  3012. sendSeq = pAdspConn->adspco_SendAttnSeq;
  3013. recvSeq = pAdspConn->adspco_RecvAttnSeq;
  3014. recvWindow = 0;
  3015. }
  3016. // Allocate the datagram buffer
  3017. if ((pBuffDesc = AtalkAllocBuffDesc(NULL,
  3018. ADSP_DATA_OFF,
  3019. BD_CHAR_BUFFER | BD_FREE_BUFFER)) != NULL)
  3020. {
  3021. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_SRC_CONNID_OFF,
  3022. pAdspConn->adspco_LocalConnId);
  3023. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_FIRST_BYTE_SEQNUM_OFF,
  3024. sendSeq);
  3025. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_NEXT_RX_BYTESEQNUM_OFF,
  3026. recvSeq);
  3027. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_RX_WINDOW_SIZE_OFF,
  3028. recvWindow);
  3029. // Set the descriptor
  3030. pBuffDesc->bd_CharBuffer[ADSP_DESCRIPTOR_OFF] = Descriptor;
  3031. }
  3032. else
  3033. {
  3034. error = ATALK_RESR_MEM;
  3035. }
  3036. }
  3037. #if DBG
  3038. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  3039. #endif
  3040. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3041. if (ATALK_SUCCESS(error))
  3042. {
  3043. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3044. ("AtalkAdspSendControl: %lx.%lx\n", pAdspConn, Descriptor));
  3045. // We let the completion routine Deref the conn.
  3046. SendInfo.sc_TransmitCompletion = atalkAdspConnSendComplete;
  3047. SendInfo.sc_Ctx1 = pAdspConn;
  3048. SendInfo.sc_Ctx2 = pBuffDesc;
  3049. // SendInfo.sc_Ctx3 = NULL;
  3050. if (!ATALK_SUCCESS(AtalkDdpSend(pAdspConn->adspco_pDdpAddr,
  3051. &pAdspConn->adspco_RemoteAddr,
  3052. DDPPROTO_ADSP,
  3053. FALSE,
  3054. pBuffDesc,
  3055. NULL,
  3056. 0,
  3057. NULL,
  3058. &SendInfo)))
  3059. {
  3060. atalkAdspConnSendComplete(NDIS_STATUS_FAILURE, &SendInfo);
  3061. }
  3062. }
  3063. else
  3064. {
  3065. if (DerefConn)
  3066. {
  3067. AtalkAdspConnDereference(pAdspConn);
  3068. }
  3069. }
  3070. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3071. #if DBG
  3072. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  3073. #endif
  3074. }
  3075. LOCAL VOID
  3076. atalkAdspSendDeny(
  3077. IN PADSP_ADDROBJ pAdspAddr,
  3078. IN PATALK_ADDR pRemoteAddr,
  3079. IN USHORT RemoteConnId
  3080. )
  3081. /*++
  3082. Routine Description:
  3083. Arguments:
  3084. Return Value:
  3085. --*/
  3086. {
  3087. ATALK_ERROR error;
  3088. PBUFFER_DESC pBuffDesc;
  3089. SEND_COMPL_INFO SendInfo;
  3090. // Allocate the datagram buffer
  3091. if ((pBuffDesc = AtalkAllocBuffDesc(NULL,
  3092. ADSP_NEXT_ATTEN_SEQNUM_OFF + sizeof(ULONG),
  3093. BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
  3094. {
  3095. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  3096. ("AtalkAdspSendControl: AtalkAllocBuffDesc failed\n"));
  3097. RES_LOG_ERROR();
  3098. return;
  3099. }
  3100. // Try to reference address for this call.
  3101. AtalkAdspAddrReference(pAdspAddr, &error);
  3102. if (!ATALK_SUCCESS(error))
  3103. {
  3104. AtalkFreeBuffDesc(pBuffDesc);
  3105. return;
  3106. }
  3107. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_SRC_CONNID_OFF, 0);
  3108. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_FIRST_BYTE_SEQNUM_OFF, 0);
  3109. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_NEXT_RX_BYTESEQNUM_OFF, 0);
  3110. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_RX_WINDOW_SIZE_OFF, 0);
  3111. // Set the descriptor
  3112. pBuffDesc->bd_CharBuffer[ADSP_DESCRIPTOR_OFF] = ADSP_CONTROL_FLAG |
  3113. ADSP_OPENCONN_DENY_CODE;
  3114. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_VERSION_STAMP_OFF,
  3115. ADSP_VERSION);
  3116. PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ADSP_DEST_CONNID_OFF,
  3117. RemoteConnId);
  3118. PUTDWORD2DWORD(pBuffDesc->bd_CharBuffer + ADSP_NEXT_ATTEN_SEQNUM_OFF,
  3119. 0);
  3120. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3121. ("AtalkAdspSendDeny: %lx.%lx\n", pAdspAddr, pBuffDesc));
  3122. // We let the completion routine Deref the conn.
  3123. SendInfo.sc_TransmitCompletion = atalkAdspAddrSendComplete;
  3124. SendInfo.sc_Ctx1 = pAdspAddr;
  3125. SendInfo.sc_Ctx2 = pBuffDesc;
  3126. // SendInfo.sc_Ctx3 = NULL;
  3127. if(!ATALK_SUCCESS(AtalkDdpSend(AtalkAdspGetDdpAddress(pAdspAddr),
  3128. pRemoteAddr,
  3129. DDPPROTO_ADSP,
  3130. FALSE,
  3131. pBuffDesc,
  3132. NULL,
  3133. 0,
  3134. NULL,
  3135. &SendInfo)))
  3136. {
  3137. atalkAdspAddrSendComplete(NDIS_STATUS_FAILURE, &SendInfo);
  3138. }
  3139. }
  3140. LOCAL VOID
  3141. atalkAdspSendAttn(
  3142. IN PADSP_CONNOBJ pAdspConn
  3143. )
  3144. /*++
  3145. Routine Description:
  3146. Arguments:
  3147. Return Value:
  3148. --*/
  3149. {
  3150. KIRQL OldIrql;
  3151. PBYTE adspHeader;
  3152. ATALK_ERROR error = ATALK_NO_ERROR;
  3153. PBUFFER_DESC pBuffDesc = NULL;
  3154. SEND_COMPL_INFO SendInfo;
  3155. do
  3156. {
  3157. pBuffDesc = AtalkAllocBuffDesc(NULL,
  3158. ADSP_DATA_OFF + ADSP_MAX_DATA_SIZE,
  3159. BD_CHAR_BUFFER | BD_FREE_BUFFER);
  3160. if (pBuffDesc == NULL)
  3161. {
  3162. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  3163. ("AtalkAdspSendAttn: AtalkAllocBuffDesc failed\n"));
  3164. RES_LOG_ERROR();
  3165. break;
  3166. }
  3167. adspHeader = pBuffDesc->bd_CharBuffer;
  3168. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  3169. if (pAdspConn->adspco_Flags & ADSPCO_EXSEND_IN_PROGRESS)
  3170. {
  3171. PUTSHORT2SHORT(adspHeader + ADSP_SRC_CONNID_OFF,
  3172. pAdspConn->adspco_LocalConnId);
  3173. PUTDWORD2DWORD(adspHeader + ADSP_THIS_ATTEN_SEQNUM_OFF,
  3174. pAdspConn->adspco_SendAttnSeq);
  3175. PUTDWORD2DWORD(adspHeader + ADSP_NEXT_RX_ATTNSEQNUM_OFF,
  3176. pAdspConn->adspco_RecvAttnSeq);
  3177. PUTSHORT2SHORT(adspHeader + ADSP_RX_ATTEN_SIZE_OFF, 0);
  3178. // Set the descriptor
  3179. adspHeader[ADSP_DESCRIPTOR_OFF] = ADSP_ATTEN_FLAG + ADSP_ACK_REQ_FLAG;
  3180. // Send eom?
  3181. if (((pAdspConn->adspco_ExWriteFlags & TDI_SEND_PARTIAL) == 0) &&
  3182. (pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_MESSAGE))
  3183. {
  3184. adspHeader[ADSP_DESCRIPTOR_OFF] += ADSP_EOM_FLAG;
  3185. }
  3186. // Copy the attention data
  3187. RtlCopyMemory(&adspHeader[ADSP_DATA_OFF],
  3188. pAdspConn->adspco_ExWriteChBuf,
  3189. pAdspConn->adspco_ExWriteBufLen);
  3190. // Set the size in the buffer descriptor
  3191. AtalkSetSizeOfBuffDescData(pBuffDesc,
  3192. ADSP_DATA_OFF +
  3193. pAdspConn->adspco_ExWriteBufLen);
  3194. }
  3195. else
  3196. {
  3197. error = ATALK_FAILURE;
  3198. }
  3199. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  3200. if (ATALK_SUCCESS(error))
  3201. {
  3202. // Send the packet
  3203. SendInfo.sc_TransmitCompletion = atalkAdspSendAttnComplete;
  3204. SendInfo.sc_Ctx1 = pAdspConn;
  3205. SendInfo.sc_Ctx2 = pBuffDesc;
  3206. // SendInfo.sc_Ctx3 = NULL;
  3207. error = AtalkDdpSend(pAdspConn->adspco_pDdpAddr,
  3208. &pAdspConn->adspco_RemoteAddr,
  3209. (BYTE)DDPPROTO_ADSP,
  3210. FALSE,
  3211. pBuffDesc,
  3212. NULL,
  3213. 0,
  3214. NULL,
  3215. &SendInfo);
  3216. if (!ATALK_SUCCESS(error))
  3217. {
  3218. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  3219. ("AtalkAdspSendAttn: DdpSend failed %ld\n", error));
  3220. atalkAdspSendAttnComplete(NDIS_STATUS_FAILURE, &SendInfo);
  3221. }
  3222. error = ATALK_PENDING;
  3223. }
  3224. } while (FALSE);
  3225. if (!ATALK_SUCCESS(error) && (pBuffDesc != NULL))
  3226. {
  3227. AtalkFreeBuffDesc(pBuffDesc);
  3228. }
  3229. }
  3230. LOCAL VOID
  3231. atalkAdspSendData(
  3232. IN PADSP_CONNOBJ pAdspConn
  3233. )
  3234. /*++
  3235. Routine Description:
  3236. MUST BE ENTERED WITH CONNECTION LOCK HELD !!!
  3237. Arguments:
  3238. Return Value:
  3239. --*/
  3240. {
  3241. ATALK_ERROR error;
  3242. BYTE descriptor;
  3243. ULONG dataSize;
  3244. BOOLEAN eom;
  3245. BYTE adspHeader[ADSP_DATA_OFF];
  3246. LONG windowSize = 0;
  3247. PBUFFER_CHUNK pBufferChunk = NULL;
  3248. PBUFFER_DESC pBuffDesc = NULL;
  3249. SEND_COMPL_INFO SendInfo;
  3250. // If there is no data to send or if the remote cannot handle any more
  3251. // data, just send an ack.
  3252. SendInfo.sc_TransmitCompletion = atalkAdspSendDataComplete;
  3253. SendInfo.sc_Ctx1 = pAdspConn;
  3254. while (TRUE)
  3255. {
  3256. if ((pAdspConn->adspco_Flags & (ADSPCO_ACTIVE |
  3257. ADSPCO_CLOSING |
  3258. ADSPCO_STOPPING |
  3259. ADSPCO_DISCONNECTING)) != ADSPCO_ACTIVE)
  3260. {
  3261. break;
  3262. }
  3263. // dataSize includes count of eom if present
  3264. dataSize = atalkAdspBufferQueueSize(&pAdspConn->adspco_NextSendQueue);
  3265. windowSize = (LONG)(pAdspConn->adspco_SendWindowSeq -
  3266. pAdspConn->adspco_SendSeq +
  3267. (LONG)1);
  3268. ASSERTMSG("WindowSize incorrect!\n",
  3269. ((windowSize >= 0) || (dataSize == 0)));
  3270. if ((dataSize == 0) || (windowSize == 0))
  3271. {
  3272. // Send a ack request to the remote end.
  3273. descriptor = ADSP_CONTROL_FLAG + ADSP_PROBE_OR_ACK_CODE +
  3274. ((windowSize == 0) ? ADSP_ACK_REQ_FLAG : 0);
  3275. atalkAdspSendControl(pAdspConn, descriptor);
  3276. break;
  3277. }
  3278. ASSERTMSG("WindowSize incorrect!\n", (windowSize >= 0));
  3279. if (windowSize < 0)
  3280. {
  3281. // This should never happen. It can be negative, but only if
  3282. // the datasize is 0.
  3283. }
  3284. // We have some data to send
  3285. windowSize = MIN((ULONG)windowSize, dataSize);
  3286. // compute the amount of data to be sent. This will only get
  3287. // the data in one buffer chunk, i.e. if the current buffer chunk
  3288. // has only one byte to be sent, it will return just that, although
  3289. // the next buffer chunk might still have some data to be sent. It will
  3290. // return a built buffer chunk with the proper amount of data in it.
  3291. // Given checks above there is guaranteed to be dataSize amount of data
  3292. // in queue.
  3293. dataSize = atalkAdspDescribeFromBufferQueue(&pAdspConn->adspco_NextSendQueue,
  3294. &eom,
  3295. windowSize,
  3296. &pBufferChunk,
  3297. &pBuffDesc);
  3298. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3299. ("atalkAdspSendData: DataSize %ld\n", dataSize));
  3300. ASSERT(dataSize <= (ULONG)windowSize);
  3301. descriptor = (eom ? ADSP_EOM_FLAG : 0);
  3302. if (windowSize == (LONG)(dataSize + BYTECOUNT(eom)))
  3303. {
  3304. descriptor += ADSP_ACK_REQ_FLAG;
  3305. }
  3306. PUTSHORT2SHORT(adspHeader + ADSP_SRC_CONNID_OFF,
  3307. pAdspConn->adspco_LocalConnId);
  3308. PUTDWORD2DWORD(adspHeader + ADSP_FIRST_BYTE_SEQNUM_OFF,
  3309. pAdspConn->adspco_SendSeq);
  3310. PUTDWORD2DWORD(adspHeader + ADSP_NEXT_RX_BYTESEQNUM_OFF,
  3311. pAdspConn->adspco_RecvSeq);
  3312. PUTSHORT2SHORT(adspHeader + ADSP_RX_WINDOW_SIZE_OFF,
  3313. pAdspConn->adspco_RecvWindow);
  3314. // Set the descriptor
  3315. adspHeader[ADSP_DESCRIPTOR_OFF] = descriptor;
  3316. // Move up our seq num. We should do it before we release the lock
  3317. // so that other calls to this routine do not mess it up.
  3318. // !!!NOTE!!! Due to calling describe, dataSize *does not* include
  3319. // eom in its count.
  3320. pAdspConn->adspco_SendSeq += (ULONG)dataSize + BYTECOUNT(eom);
  3321. windowSize -= dataSize;
  3322. #if DBG
  3323. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  3324. #endif
  3325. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3326. // Send the packet
  3327. SendInfo.sc_Ctx2 = pBuffDesc;
  3328. SendInfo.sc_Ctx3 = pBufferChunk;
  3329. error = AtalkDdpSend(pAdspConn->adspco_pDdpAddr,
  3330. &pAdspConn->adspco_RemoteAddr,
  3331. (BYTE)DDPPROTO_ADSP,
  3332. FALSE,
  3333. pBuffDesc,
  3334. adspHeader,
  3335. sizeof(adspHeader),
  3336. NULL,
  3337. &SendInfo);
  3338. if (!ATALK_SUCCESS(error))
  3339. {
  3340. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  3341. ("AtalkAdspSendData: DdpSend failed %ld\n", error));
  3342. atalkAdspSendDataComplete(NDIS_STATUS_FAILURE, &SendInfo);
  3343. }
  3344. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3345. #if DBG
  3346. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  3347. #endif
  3348. }
  3349. }
  3350. LOCAL VOID
  3351. atalkAdspRecvData(
  3352. IN PADSP_CONNOBJ pAdspConn
  3353. )
  3354. /*++
  3355. Routine Description:
  3356. MUST HAVE THE CONNECTION LOCK HELD BEFORE ENTERING HERE !!!
  3357. SHOULD THIS ROUTINE HAVE ITS OWN REFERENCE FOR THE CONNECTION?
  3358. Arguments:
  3359. Return Value:
  3360. --*/
  3361. {
  3362. BOOLEAN eom;
  3363. ULONG msgSize, readSize, bytesTaken, bytesRead;
  3364. ULONG lookaheadSize;
  3365. PBYTE lookaheadData;
  3366. ULONG readFlags;
  3367. PAMDL readBuf;
  3368. USHORT readBufLen;
  3369. GENERIC_READ_COMPLETION readCompletion;
  3370. PVOID readCtx;
  3371. PIRP recvIrp;
  3372. PTDI_IND_RECEIVE recvHandler;
  3373. PVOID recvHandlerCtx;
  3374. NTSTATUS ntStatus;
  3375. BOOLEAN callComp = FALSE, fWdwChanged = FALSE;
  3376. ATALK_ERROR ErrorCode;
  3377. do
  3378. {
  3379. if ((pAdspConn->adspco_Flags &
  3380. (ADSPCO_READ_PENDING | ADSPCO_FORWARD_RESET_RECD)) ==
  3381. (ADSPCO_READ_PENDING | ADSPCO_FORWARD_RESET_RECD))
  3382. {
  3383. readFlags = pAdspConn->adspco_ReadFlags;
  3384. readBuf = pAdspConn->adspco_ReadBuf;
  3385. readBufLen = pAdspConn->adspco_ReadBufLen;
  3386. readCompletion = pAdspConn->adspco_ReadCompletion;
  3387. readCtx = pAdspConn->adspco_ReadCtx;
  3388. pAdspConn->adspco_Flags &= ~ADSPCO_READ_PENDING;
  3389. #if DBG
  3390. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  3391. #endif
  3392. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3393. if (*readCompletion != NULL)
  3394. {
  3395. (*readCompletion)(ATALK_ADSP_CONN_RESET,
  3396. readBuf,
  3397. readBufLen,
  3398. readFlags,
  3399. readCtx);
  3400. }
  3401. // Deref connection for the read
  3402. AtalkAdspConnDereference(pAdspConn);
  3403. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3404. #if DBG
  3405. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  3406. #endif
  3407. break;
  3408. }
  3409. // Check for pending attention data
  3410. if (pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_RECD)
  3411. {
  3412. atalkAdspRecvAttn(pAdspConn);
  3413. }
  3414. // Get the receive handler.
  3415. recvHandler = pAdspConn->adspco_pAssocAddr->adspao_RecvHandler;
  3416. recvHandlerCtx = pAdspConn->adspco_pAssocAddr->adspao_RecvHandlerCtx;
  3417. // !!!NOTE!!!
  3418. // Its possible that when we get a disconnect packet before we
  3419. // get previously sent data, we could end up indicating disconnect
  3420. // to afd before indicating the received data. This hits an assertion
  3421. // in afd on a checked build, but afd still behaves as it should.
  3422. msgSize = atalkAdspMessageSize(&pAdspConn->adspco_RecvQueue, &eom);
  3423. bytesRead = 1; // A Non-zero value so we enter the loop
  3424. while (((msgSize > 0) || eom) && (bytesRead > 0))
  3425. {
  3426. bytesRead = 0;
  3427. // Check for no pending reads, but we have new data to indicate, and the
  3428. // client has read all the previously indicated data.
  3429. if (((pAdspConn->adspco_Flags & ADSPCO_READ_PENDING) == 0) &&
  3430. (*recvHandler != NULL) &&
  3431. (pAdspConn->adspco_PrevIndicatedData == 0))
  3432. {
  3433. pAdspConn->adspco_PrevIndicatedData = msgSize;
  3434. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3435. ("atalkAdspRecvData: PrevInd1 %d\n", pAdspConn->adspco_PrevIndicatedData));
  3436. lookaheadData = atalkAdspGetLookahead(&pAdspConn->adspco_RecvQueue,
  3437. &lookaheadSize);
  3438. readFlags = ((eom) ?
  3439. (TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE) :
  3440. (TDI_RECEIVE_PARTIAL | TDI_RECEIVE_NORMAL));
  3441. if (*recvHandler != NULL)
  3442. {
  3443. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3444. ("atalkAdspRecvData: Indicating data %ld.%ld!\n", lookaheadSize, msgSize));
  3445. #if DBG
  3446. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  3447. #endif
  3448. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3449. ntStatus = (*recvHandler)(recvHandlerCtx,
  3450. pAdspConn->adspco_ConnCtx,
  3451. readFlags,
  3452. lookaheadSize,
  3453. msgSize,
  3454. &bytesTaken,
  3455. lookaheadData,
  3456. &recvIrp);
  3457. ASSERT((bytesTaken == 0) || (bytesTaken == msgSize));
  3458. if (ntStatus == STATUS_MORE_PROCESSING_REQUIRED)
  3459. {
  3460. if (recvIrp != NULL)
  3461. {
  3462. // Post the receive as if it came from the io system
  3463. ntStatus = AtalkDispatchInternalDeviceControl(
  3464. (PDEVICE_OBJECT)AtalkDeviceObject[ATALK_DEV_ADSP],
  3465. recvIrp);
  3466. ASSERT(ntStatus == STATUS_PENDING);
  3467. }
  3468. else
  3469. {
  3470. ASSERTMSG("atalkAdspRecvData: No receive irp!\n", 0);
  3471. KeBugCheck(0);
  3472. }
  3473. }
  3474. else if (ntStatus == STATUS_SUCCESS)
  3475. {
  3476. if (bytesTaken != 0)
  3477. {
  3478. // Assume all of the data was read.
  3479. ASSERT(bytesTaken == msgSize);
  3480. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3481. ("atalkAdspRecvData: All bytes read %lx\n", bytesTaken));
  3482. // Discard data from queue (msgSize + BYTECOUNT(eom))
  3483. // amount of data).
  3484. }
  3485. }
  3486. else if (ntStatus == STATUS_DATA_NOT_ACCEPTED)
  3487. {
  3488. // Client may have posted a receive in the indication. Or
  3489. // it will post a receive later on. Do nothing here.
  3490. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3491. ("atalkAdspRecvData: Indication status %lx\n", ntStatus));
  3492. }
  3493. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3494. #if DBG
  3495. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  3496. #endif
  3497. }
  3498. }
  3499. // Check for any posted receives, this may have happened during
  3500. // the receive indication.
  3501. if (pAdspConn->adspco_Flags & ADSPCO_READ_PENDING)
  3502. {
  3503. readFlags = pAdspConn->adspco_ReadFlags;
  3504. readBuf = pAdspConn->adspco_ReadBuf;
  3505. readBufLen = pAdspConn->adspco_ReadBufLen;
  3506. readCompletion = pAdspConn->adspco_ReadCompletion;
  3507. readCtx = pAdspConn->adspco_ReadCtx;
  3508. // For a message-based socket, we do not complete
  3509. // a read until eom, or the buffer fills up.
  3510. if ((pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_MESSAGE) &&
  3511. (!eom && (msgSize < readBufLen)))
  3512. {
  3513. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3514. ("atalkAdspRecv: MsgSize < readLen %lx.%lx\n", msgSize, readBufLen));
  3515. // If we are disconnected and this data is just the last
  3516. // remnant from remote, we just copy what we got and leave.
  3517. // There may not have been an EOM from the remote.
  3518. // Also, if the msg is bigger than what transport can hold (8K),
  3519. // give whatever we have so far to the app so that our recv window
  3520. // can open up. That is, break out of the loop only if recv window
  3521. // has room to accept more data
  3522. if ( (pAdspConn->adspco_Flags & ADSPCO_ACTIVE) &&
  3523. (pAdspConn->adspco_RecvWindow > 1))
  3524. {
  3525. break;
  3526. }
  3527. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  3528. ("AtalkAdspRead: READ AFTER DISC %lx Flg %lx\n",
  3529. pAdspConn, pAdspConn->adspco_Flags));
  3530. }
  3531. // This will return the data in the mdl from the
  3532. // receive queue.
  3533. readSize = atalkAdspReadFromBufferQueue(&pAdspConn->adspco_RecvQueue,
  3534. readFlags,
  3535. readBuf,
  3536. &readBufLen,
  3537. &eom);
  3538. if ((readSize == 0) && !eom)
  3539. {
  3540. pAdspConn->adspco_PrevIndicatedData = 0;
  3541. break;
  3542. }
  3543. bytesRead += (readSize + BYTECOUNT(eom));
  3544. pAdspConn->adspco_Flags &= ~ADSPCO_READ_PENDING;
  3545. // If this is not a PEEK receive, the data will be
  3546. // discarded from the queue. If so, increase our window size, do a
  3547. // senddata to let remote know of the change.
  3548. if ((readFlags & TDI_RECEIVE_PEEK) == 0)
  3549. {
  3550. pAdspConn->adspco_RecvWindow += (readSize + BYTECOUNT(eom));
  3551. ASSERT(pAdspConn->adspco_RecvWindow <=
  3552. pAdspConn->adspco_RecvQueueMax);
  3553. fWdwChanged = TRUE;
  3554. }
  3555. #if DBG
  3556. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  3557. #endif
  3558. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3559. if (*readCompletion != NULL)
  3560. {
  3561. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3562. ("atalkAdspRecvData: Read for %d, %x\n", readBufLen, readFlags));
  3563. ErrorCode = ATALK_NO_ERROR;
  3564. if ((pAdspConn->adspco_pAssocAddr->adspao_Flags & ADSPAO_MESSAGE) && !eom)
  3565. {
  3566. ErrorCode = ATALK_ADSP_PARTIAL_RECEIVE;
  3567. }
  3568. (*readCompletion)(ErrorCode,
  3569. readBuf,
  3570. readBufLen,
  3571. readFlags,
  3572. readCtx);
  3573. }
  3574. // Deref connection for the read
  3575. AtalkAdspConnDereference(pAdspConn);
  3576. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3577. #if DBG
  3578. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  3579. #endif
  3580. // Now change our prev indicated field. Until we
  3581. // complete the read, we musn't indicate new data.
  3582. // If the read was PEEK, then we don't want to do
  3583. // any more indications until a *real* read happens.
  3584. if ((readFlags & TDI_RECEIVE_PEEK) == 0)
  3585. {
  3586. pAdspConn->adspco_PrevIndicatedData -=
  3587. MIN(readSize, pAdspConn->adspco_PrevIndicatedData);
  3588. }
  3589. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3590. ("atalkAdspRecvData: PrevInd2 %d\n",
  3591. pAdspConn->adspco_PrevIndicatedData));
  3592. }
  3593. msgSize = atalkAdspMessageSize(&pAdspConn->adspco_RecvQueue, &eom);
  3594. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3595. ("Second msg %d.%d\n", msgSize, eom));
  3596. }
  3597. } while (FALSE);
  3598. if (fWdwChanged &&
  3599. (pAdspConn->adspco_PrevIndicatedData == 0))
  3600. {
  3601. atalkAdspSendData(pAdspConn);
  3602. }
  3603. }
  3604. LOCAL VOID
  3605. atalkAdspRecvAttn(
  3606. IN PADSP_CONNOBJ pAdspConn
  3607. )
  3608. /*++
  3609. Routine Description:
  3610. !!!THIS ROUTINE MUST PRESERVE THE STATE OF THE CONNECTION LOCK!!!
  3611. SHOULD THIS ROUTINE HAVE ITS OWN REFERENCE FOR THE CONNECTION?
  3612. Arguments:
  3613. Return Value:
  3614. --*/
  3615. {
  3616. ATALK_ERROR error;
  3617. PAMDL readBuf;
  3618. USHORT readBufLen;
  3619. ULONG readFlags;
  3620. GENERIC_READ_COMPLETION readCompletion;
  3621. PVOID readCtx;
  3622. PBYTE attnData;
  3623. USHORT attnDataSize;
  3624. ULONG bytesRead;
  3625. NTSTATUS status;
  3626. do
  3627. {
  3628. if ((pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_RECD) == 0)
  3629. {
  3630. break;
  3631. }
  3632. if (pAdspConn->adspco_Flags & ADSPCO_EXREAD_PENDING)
  3633. {
  3634. // Use the expedited receive posted
  3635. readFlags = pAdspConn->adspco_ExReadFlags;
  3636. readBuf = pAdspConn->adspco_ExReadBuf;
  3637. readBufLen = pAdspConn->adspco_ExReadBufLen;
  3638. readCompletion = pAdspConn->adspco_ExReadCompletion;
  3639. readCtx = pAdspConn->adspco_ExReadCtx;
  3640. pAdspConn->adspco_Flags &= ~ADSPCO_EXREAD_PENDING;
  3641. }
  3642. else if ((pAdspConn->adspco_Flags & ADSPCO_READ_PENDING) &&
  3643. (pAdspConn->adspco_ReadFlags & TDI_RECEIVE_EXPEDITED))
  3644. {
  3645. // Use the normal receive
  3646. readFlags = pAdspConn->adspco_ReadFlags;
  3647. readBuf = pAdspConn->adspco_ReadBuf;
  3648. readBufLen = pAdspConn->adspco_ReadBufLen;
  3649. readCompletion = pAdspConn->adspco_ReadCompletion;
  3650. readCtx = pAdspConn->adspco_ReadCtx;
  3651. pAdspConn->adspco_Flags &= ~ADSPCO_READ_PENDING;
  3652. }
  3653. else
  3654. {
  3655. break;
  3656. }
  3657. attnData = pAdspConn->adspco_ExRecdData;
  3658. attnDataSize = pAdspConn->adspco_ExRecdLen;
  3659. // Copy received attention data into the read buffer
  3660. error = ATALK_ADSP_PAREXPED_RECEIVE;
  3661. if (pAdspConn->adspco_Flags & ADSPCO_ATTN_DATA_EOM)
  3662. {
  3663. error = ATALK_ADSP_EXPED_RECEIVE;
  3664. }
  3665. if (attnDataSize > readBufLen)
  3666. {
  3667. attnDataSize = readBufLen;
  3668. }
  3669. status = TdiCopyBufferToMdl(attnData,
  3670. 0,
  3671. attnDataSize,
  3672. readBuf,
  3673. 0,
  3674. &bytesRead);
  3675. ASSERT(NT_SUCCESS(status) && (attnDataSize == bytesRead));
  3676. // Update sequence number etc., only if this was not a peek.
  3677. if ((readFlags & TDI_RECEIVE_PEEK) == 0)
  3678. {
  3679. pAdspConn->adspco_ExRecdData = NULL;
  3680. // Advance our receive attention sequence number
  3681. pAdspConn->adspco_RecvAttnSeq += 1;
  3682. pAdspConn->adspco_Flags &= ~(ADSPCO_ATTN_DATA_RECD |
  3683. ADSPCO_ATTN_DATA_EOM);
  3684. }
  3685. #if DBG
  3686. (&pAdspConn->adspco_Lock)->FileLineLock |= 0x80000000;
  3687. #endif
  3688. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3689. // Complete receive
  3690. ASSERT(*readCompletion != NULL);
  3691. (*readCompletion)(error,
  3692. readBuf,
  3693. attnDataSize,
  3694. TDI_RECEIVE_EXPEDITED,
  3695. readCtx);
  3696. // Free the allocated buffer if this was not a peek
  3697. if ((readFlags & TDI_RECEIVE_PEEK) == 0)
  3698. {
  3699. AtalkFreeMemory(attnData);
  3700. }
  3701. // Deref connection for the read
  3702. AtalkAdspConnDereference(pAdspConn);
  3703. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3704. #if DBG
  3705. (&pAdspConn->adspco_Lock)->FileLineLock &= ~0x80000000;
  3706. #endif
  3707. // Send ack for the attention only if this was not a peek
  3708. if ((readFlags & TDI_RECEIVE_PEEK) == 0)
  3709. {
  3710. atalkAdspSendControl(pAdspConn,
  3711. ADSP_CONTROL_FLAG + ADSP_ATTEN_FLAG);
  3712. }
  3713. } while (FALSE);
  3714. }
  3715. VOID FASTCALL
  3716. atalkAdspConnSendComplete(
  3717. IN NDIS_STATUS Status,
  3718. IN PSEND_COMPL_INFO pSendInfo
  3719. )
  3720. /*++
  3721. Routine Description:
  3722. Arguments:
  3723. Return Value:
  3724. --*/
  3725. {
  3726. if (pSendInfo->sc_Ctx2 != NULL)
  3727. {
  3728. AtalkFreeBuffDesc((PBUFFER_DESC)(pSendInfo->sc_Ctx2));
  3729. }
  3730. AtalkAdspConnDereference((PADSP_CONNOBJ)(pSendInfo->sc_Ctx1));
  3731. }
  3732. VOID FASTCALL
  3733. atalkAdspAddrSendComplete(
  3734. IN NDIS_STATUS Status,
  3735. IN PSEND_COMPL_INFO pSendInfo
  3736. )
  3737. /*++
  3738. Routine Description:
  3739. Arguments:
  3740. Return Value:
  3741. --*/
  3742. {
  3743. if (pSendInfo->sc_Ctx2 != NULL)
  3744. {
  3745. AtalkFreeBuffDesc((PBUFFER_DESC)(pSendInfo->sc_Ctx2));
  3746. }
  3747. AtalkAdspAddrDereference((PADSP_ADDROBJ)(pSendInfo->sc_Ctx1));
  3748. }
  3749. VOID FASTCALL
  3750. atalkAdspSendAttnComplete(
  3751. IN NDIS_STATUS Status,
  3752. IN PSEND_COMPL_INFO pSendInfo
  3753. )
  3754. /*++
  3755. Routine Description:
  3756. Arguments:
  3757. Return Value:
  3758. --*/
  3759. {
  3760. if (pSendInfo->sc_Ctx2 != NULL)
  3761. {
  3762. AtalkFreeBuffDesc((PBUFFER_DESC)(pSendInfo->sc_Ctx2));
  3763. }
  3764. }
  3765. VOID FASTCALL
  3766. atalkAdspSendDataComplete(
  3767. IN NDIS_STATUS Status,
  3768. IN PSEND_COMPL_INFO pSendInfo
  3769. )
  3770. /*++
  3771. Routine Description:
  3772. Arguments:
  3773. Return Value:
  3774. --*/
  3775. {
  3776. if (pSendInfo->sc_Ctx2 != NULL)
  3777. {
  3778. AtalkFreeBuffDesc((PBUFFER_DESC)(pSendInfo->sc_Ctx2));
  3779. }
  3780. if (pSendInfo->sc_Ctx3 != NULL)
  3781. {
  3782. atalkAdspBufferChunkDereference((PBUFFER_CHUNK)(pSendInfo->sc_Ctx3),
  3783. FALSE,
  3784. NULL);
  3785. }
  3786. }
  3787. //
  3788. // ADSP TIMER ROUTINES
  3789. //
  3790. LOCAL LONG FASTCALL
  3791. atalkAdspConnMaintenanceTimer(
  3792. IN PTIMERLIST pTimer,
  3793. IN BOOLEAN TimerShuttingDown
  3794. )
  3795. /*++
  3796. Routine Description:
  3797. Arguments:
  3798. Return Value:
  3799. --*/
  3800. {
  3801. PADSP_CONNOBJ pAdspConn;
  3802. LONG now;
  3803. BOOLEAN done = FALSE;
  3804. pAdspConn = (PADSP_CONNOBJ)CONTAINING_RECORD(pTimer, ADSP_CONNOBJ, adspco_ConnTimer);
  3805. ASSERT(VALID_ADSPCO(pAdspConn));
  3806. if (TimerShuttingDown)
  3807. {
  3808. done = TRUE;
  3809. }
  3810. else
  3811. {
  3812. ASSERT(VALID_ADSPCO(pAdspConn));
  3813. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3814. if (pAdspConn->adspco_Flags & ( ADSPCO_CLOSING |
  3815. ADSPCO_STOPPING |
  3816. ADSPCO_DISCONNECTING))
  3817. {
  3818. done = TRUE;
  3819. }
  3820. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3821. }
  3822. if (done)
  3823. {
  3824. // Dereference connection for the timer.
  3825. AtalkAdspConnDereference(pAdspConn);
  3826. return ATALK_TIMER_NO_REQUEUE;
  3827. }
  3828. now = AtalkGetCurrentTick();
  3829. if ((now - pAdspConn->adspco_LastContactTime) > ADSP_CONNECTION_INTERVAL)
  3830. {
  3831. // Connection has expired.
  3832. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  3833. ("atalkAdspConnMaintenanceTimer: Connection %lx.%lx expired\n",
  3834. pAdspConn, pAdspConn->adspco_LocalConnId));
  3835. AtalkAdspDisconnect(pAdspConn,
  3836. ATALK_TIMER_DISCONNECT,
  3837. NULL,
  3838. NULL);
  3839. // Dereference connection for the timer.
  3840. AtalkAdspConnDereference(pAdspConn);
  3841. return ATALK_TIMER_NO_REQUEUE;
  3842. }
  3843. // If we have not heard from the other side recently, send out a
  3844. // probe.
  3845. if ((now - pAdspConn->adspco_LastContactTime) > (ADSP_PROBE_INTERVAL/ATALK_TIMER_FACTOR))
  3846. {
  3847. KIRQL OldIrql;
  3848. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_WARN,
  3849. ("atalkAdspConnMaintenanceTimer: Connection %lx.%lx sending probe\n",
  3850. pAdspConn, pAdspConn->adspco_LocalConnId));
  3851. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  3852. atalkAdspSendControl(pAdspConn,
  3853. ADSP_CONTROL_FLAG + ADSP_ACK_REQ_FLAG + ADSP_PROBE_OR_ACK_CODE);
  3854. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  3855. }
  3856. return ATALK_TIMER_REQUEUE;
  3857. }
  3858. LOCAL LONG FASTCALL
  3859. atalkAdspRetransmitTimer(
  3860. IN PTIMERLIST pTimer,
  3861. IN BOOLEAN TimerShuttingDown
  3862. )
  3863. /*++
  3864. Routine Description:
  3865. Arguments:
  3866. Return Value:
  3867. --*/
  3868. {
  3869. PADSP_CONNOBJ pAdspConn;
  3870. BOOLEAN done = FALSE;
  3871. KIRQL OldIrql;
  3872. pAdspConn = (PADSP_CONNOBJ)CONTAINING_RECORD(pTimer, ADSP_CONNOBJ, adspco_RetransmitTimer);
  3873. ASSERT(VALID_ADSPCO(pAdspConn));
  3874. // BUG #19777: Since this routine could end up calling SendData which
  3875. // releases/acquires lock and assumes lock was acquired using the normal
  3876. // acquire spin lock, we can't use ACQUIRE_SPIN_LOCK_DPC here. Not a big
  3877. // deal as this is the retransmit case.
  3878. // ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3879. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  3880. if (TimerShuttingDown)
  3881. {
  3882. done = TRUE;
  3883. }
  3884. else
  3885. {
  3886. ASSERT(VALID_ADSPCO(pAdspConn));
  3887. if (pAdspConn->adspco_Flags & ( ADSPCO_CLOSING |
  3888. ADSPCO_STOPPING |
  3889. ADSPCO_DISCONNECTING))
  3890. {
  3891. done = TRUE;
  3892. }
  3893. }
  3894. if (done)
  3895. {
  3896. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  3897. // Dereference connection for the timer.
  3898. AtalkAdspConnDereference(pAdspConn);
  3899. return ATALK_TIMER_NO_REQUEUE;
  3900. }
  3901. // We only send data if the remote has not accepted any data from the last
  3902. // time we fired. AND we have previously sent but still unacked data pending.
  3903. if ((pAdspConn->adspco_FirstRtmtSeq == pAdspConn->adspco_LastTimerRtmtSeq) &&
  3904. (atalkAdspBufferQueueSize(&pAdspConn->adspco_SendQueue) >
  3905. atalkAdspBufferQueueSize(&pAdspConn->adspco_NextSendQueue)))
  3906. {
  3907. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3908. ("atalkAdspConnRetransmitTimer: Conn %lx Sending Data from %lx\n",
  3909. pAdspConn, pAdspConn->adspco_FirstRtmtSeq));
  3910. // Rewind sequence number and resend
  3911. pAdspConn->adspco_SendSeq = pAdspConn->adspco_FirstRtmtSeq;
  3912. pAdspConn->adspco_NextSendQueue = pAdspConn->adspco_SendQueue;
  3913. atalkAdspSendData(pAdspConn);
  3914. }
  3915. else
  3916. {
  3917. pAdspConn->adspco_LastTimerRtmtSeq = pAdspConn->adspco_FirstRtmtSeq;
  3918. }
  3919. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  3920. return ATALK_TIMER_REQUEUE;
  3921. }
  3922. LOCAL LONG FASTCALL
  3923. atalkAdspAttnRetransmitTimer(
  3924. IN PTIMERLIST pTimer,
  3925. IN BOOLEAN TimerShuttingDown
  3926. )
  3927. /*++
  3928. Routine Description:
  3929. Arguments:
  3930. Return Value:
  3931. --*/
  3932. {
  3933. PADSP_CONNOBJ pAdspConn;
  3934. pAdspConn = (PADSP_CONNOBJ)CONTAINING_RECORD(pTimer, ADSP_CONNOBJ, adspco_ExRetryTimer);
  3935. ASSERT(VALID_ADSPCO(pAdspConn));
  3936. if (TimerShuttingDown)
  3937. {
  3938. return ATALK_TIMER_NO_REQUEUE;
  3939. }
  3940. atalkAdspSendAttn(pAdspConn);
  3941. return ATALK_TIMER_REQUEUE;
  3942. }
  3943. LOCAL LONG FASTCALL
  3944. atalkAdspOpenTimer(
  3945. IN PTIMERLIST pTimer,
  3946. IN BOOLEAN TimerShuttingDown
  3947. )
  3948. /*++
  3949. Routine Description:
  3950. Arguments:
  3951. Return Value:
  3952. --*/
  3953. {
  3954. PADSP_CONNOBJ pAdspConn;
  3955. ATALK_ERROR error;
  3956. BOOLEAN done = FALSE;
  3957. pAdspConn = (PADSP_CONNOBJ)CONTAINING_RECORD(pTimer, ADSP_CONNOBJ, adspco_OpenTimer);
  3958. ASSERT(VALID_ADSPCO(pAdspConn));
  3959. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3960. ("atalkAdspOpenTimer: Entered \n"));
  3961. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3962. // If the timer is shutting down, or if we have gone active, return
  3963. if ((TimerShuttingDown) ||
  3964. (pAdspConn->adspco_Flags & ADSPCO_ACTIVE) ||
  3965. ((pAdspConn->adspco_Flags & ADSPCO_OPEN_TIMER) == 0))
  3966. {
  3967. pAdspConn->adspco_Flags &= ~ADSPCO_OPEN_TIMER;
  3968. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3969. AtalkAdspConnDereference(pAdspConn);
  3970. return ATALK_TIMER_NO_REQUEUE;
  3971. }
  3972. if ((pAdspConn->adspco_Flags & (ADSPCO_CLOSING |
  3973. ADSPCO_STOPPING |
  3974. ADSPCO_DISCONNECTING)) ||
  3975. (pAdspConn->adspco_ConnectAttempts == 0))
  3976. {
  3977. done = TRUE;
  3978. }
  3979. else
  3980. {
  3981. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  3982. ("atalkAdspOpenTimer: Connect attempt %d\n", pAdspConn->adspco_ConnectAttempts));
  3983. ASSERT(pAdspConn->adspco_ConnectAttempts > 0);
  3984. pAdspConn->adspco_ConnectAttempts--;
  3985. }
  3986. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  3987. if (!done)
  3988. {
  3989. // Resend the open request.
  3990. atalkAdspSendOpenControl(pAdspConn);
  3991. }
  3992. else
  3993. {
  3994. error = AtalkAdspDisconnect(pAdspConn,
  3995. ATALK_TIMER_DISCONNECT,
  3996. NULL,
  3997. NULL);
  3998. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_ERR,
  3999. ("atalkAdspOpenTimer: Disconnect %lx\n", error));
  4000. AtalkAdspConnDereference(pAdspConn);
  4001. }
  4002. return (done ? ATALK_TIMER_NO_REQUEUE : ATALK_TIMER_REQUEUE);
  4003. }
  4004. LOCAL LONG FASTCALL
  4005. atalkAdspDisconnectTimer(
  4006. IN PTIMERLIST pTimer,
  4007. IN BOOLEAN TimerShuttingDown
  4008. )
  4009. /*++
  4010. Routine Description:
  4011. Arguments:
  4012. Return Value:
  4013. --*/
  4014. {
  4015. PADSP_CONNOBJ pAdspConn;
  4016. pAdspConn = (PADSP_CONNOBJ)CONTAINING_RECORD(pTimer, ADSP_CONNOBJ, adspco_DisconnectTimer);
  4017. ASSERT(VALID_ADSPCO(pAdspConn));
  4018. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4019. ("atalkAdspDisconnectTimer: Entered \n"));
  4020. AtalkAdspDisconnect(pAdspConn,
  4021. ATALK_REMOTE_DISCONNECT,
  4022. NULL,
  4023. NULL);
  4024. AtalkAdspConnDereference(pAdspConn);
  4025. return ATALK_TIMER_NO_REQUEUE;
  4026. }
  4027. //
  4028. // ADSP REFERENCE/DerefERENCE ROUTINES
  4029. //
  4030. VOID
  4031. atalkAdspAddrRefNonInterlock(
  4032. IN PADSP_ADDROBJ pAdspAddr,
  4033. OUT PATALK_ERROR pError
  4034. )
  4035. /*++
  4036. Routine Description:
  4037. Arguments:
  4038. Return Value:
  4039. --*/
  4040. {
  4041. *pError = ATALK_NO_ERROR;
  4042. if (pAdspAddr == NULL)
  4043. {
  4044. *pError = ATALK_INVALID_ADDRESS;
  4045. return;
  4046. }
  4047. if ((pAdspAddr->adspao_Flags & ADSPAO_CLOSING) == 0)
  4048. {
  4049. ASSERT(pAdspAddr->adspao_RefCount >= 1);
  4050. pAdspAddr->adspao_RefCount++;
  4051. }
  4052. else
  4053. {
  4054. *pError = ATALK_ADSP_ADDR_CLOSING;
  4055. }
  4056. }
  4057. VOID
  4058. atalkAdspAddrDeref(
  4059. IN PADSP_ADDROBJ pAdspAddr
  4060. )
  4061. /*++
  4062. Routine Description:
  4063. Arguments:
  4064. Return Value:
  4065. --*/
  4066. {
  4067. BOOLEAN done = FALSE;
  4068. KIRQL OldIrql;
  4069. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  4070. ASSERT(pAdspAddr->adspao_RefCount > 0);
  4071. if (--pAdspAddr->adspao_RefCount == 0)
  4072. {
  4073. done = TRUE;
  4074. ASSERT(pAdspAddr->adspao_Flags & ADSPAO_CLOSING);
  4075. }
  4076. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  4077. if (done)
  4078. {
  4079. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4080. ("atalkAdspAddrDeref: Addr %lx done with.\n", pAdspAddr));
  4081. // Close the DDP Address Object. This should only be done after
  4082. // all the connections are gone.
  4083. AtalkDdpCloseAddress(pAdspAddr->adspao_pDdpAddr, NULL, NULL);
  4084. if (*pAdspAddr->adspao_CloseComp != NULL)
  4085. {
  4086. (*pAdspAddr->adspao_CloseComp)(ATALK_NO_ERROR,
  4087. pAdspAddr->adspao_CloseCtx);
  4088. }
  4089. // Remove from the global list.
  4090. atalkAdspAddrDeQueueGlobalList(pAdspAddr);
  4091. AtalkFreeMemory(pAdspAddr);
  4092. AtalkUnlockAdspIfNecessary();
  4093. }
  4094. }
  4095. VOID
  4096. atalkAdspConnRefByPtrNonInterlock(
  4097. IN PADSP_CONNOBJ pAdspConn,
  4098. IN ULONG NumCount,
  4099. OUT PATALK_ERROR pError
  4100. )
  4101. /*++
  4102. Routine Description:
  4103. Arguments:
  4104. Return Value:
  4105. --*/
  4106. {
  4107. *pError = ATALK_NO_ERROR;
  4108. ASSERT(VALID_ADSPCO(pAdspConn));
  4109. if (pAdspConn == NULL)
  4110. {
  4111. *pError = ATALK_INVALID_CONNECTION;
  4112. return;
  4113. }
  4114. if ((pAdspConn->adspco_Flags & ADSPCO_CLOSING) == 0)
  4115. {
  4116. ASSERT(pAdspConn->adspco_RefCount >= 1);
  4117. ASSERT(NumCount > 0);
  4118. pAdspConn->adspco_RefCount += NumCount;
  4119. }
  4120. else
  4121. {
  4122. *pError = ATALK_ADSP_CONN_CLOSING;
  4123. }
  4124. }
  4125. VOID
  4126. atalkAdspConnRefByCtxNonInterlock(
  4127. IN PADSP_ADDROBJ pAdspAddr,
  4128. IN CONNECTION_CONTEXT Ctx,
  4129. OUT PADSP_CONNOBJ * pAdspConn,
  4130. OUT PATALK_ERROR pError
  4131. )
  4132. /*++
  4133. Routine Description:
  4134. !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
  4135. Arguments:
  4136. Return Value:
  4137. --*/
  4138. {
  4139. PADSP_CONNOBJ pAdspChkConn;
  4140. *pError = ATALK_ADSP_CONN_NOT_FOUND;
  4141. for (pAdspChkConn = pAdspAddr->adspao_pAssocConn;
  4142. pAdspChkConn != NULL;
  4143. pAdspChkConn = pAdspChkConn->adspco_pNextAssoc)
  4144. {
  4145. if (pAdspChkConn->adspco_ConnCtx == Ctx)
  4146. {
  4147. AtalkAdspConnReferenceByPtr(pAdspChkConn, pError);
  4148. if (ATALK_SUCCESS(*pError))
  4149. {
  4150. *pAdspConn = pAdspChkConn;
  4151. }
  4152. break;
  4153. }
  4154. }
  4155. }
  4156. VOID
  4157. atalkAdspConnRefBySrcAddr(
  4158. IN PADSP_ADDROBJ pAdspAddr,
  4159. IN PATALK_ADDR pRemoteAddr,
  4160. IN USHORT RemoteConnId,
  4161. OUT PADSP_CONNOBJ * ppAdspConn,
  4162. OUT PATALK_ERROR pError
  4163. )
  4164. /*++
  4165. Routine Description:
  4166. !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
  4167. Arguments:
  4168. Return Value:
  4169. --*/
  4170. {
  4171. ULONG index;
  4172. PADSP_CONNOBJ pAdspConn;
  4173. // Thread the connection object into addr lookup by session id.
  4174. index = HASH_ID_SRCADDR(RemoteConnId, pRemoteAddr);
  4175. index %= ADSP_CONN_HASH_SIZE;
  4176. for (pAdspConn = pAdspAddr->adspao_pActiveHash[index];
  4177. pAdspConn != NULL;
  4178. pAdspConn = pAdspConn->adspco_pNextActive)
  4179. {
  4180. if ((pAdspConn->adspco_RemoteConnId == RemoteConnId) &&
  4181. (ATALK_ADDRS_EQUAL(&pAdspConn->adspco_RemoteAddr, pRemoteAddr)))
  4182. {
  4183. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4184. ("atalkAdspConnRefBySrcAddr: Found %lx\n", pAdspConn));
  4185. break;
  4186. }
  4187. }
  4188. *pError = ATALK_INVALID_CONNECTION;
  4189. if (pAdspConn != NULL)
  4190. {
  4191. KIRQL OldIrql;
  4192. // Check state to make sure we are not disconnecting/stopping/closing.
  4193. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  4194. if ((pAdspConn->adspco_Flags & (ADSPCO_ACTIVE | ADSPCO_HALF_ACTIVE)) &&
  4195. ((pAdspConn->adspco_Flags & (ADSPCO_CLOSING |
  4196. ADSPCO_STOPPING|
  4197. ADSPCO_DISCONNECTING)) == 0))
  4198. {
  4199. pAdspConn->adspco_RefCount++;
  4200. *pError = ATALK_NO_ERROR;
  4201. *ppAdspConn = pAdspConn;
  4202. }
  4203. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  4204. }
  4205. }
  4206. VOID
  4207. atalkAdspConnRefNextNc(
  4208. IN PADSP_CONNOBJ pAdspConn,
  4209. IN PADSP_CONNOBJ * ppAdspConnNext,
  4210. OUT PATALK_ERROR pError
  4211. )
  4212. /*++
  4213. Routine Description:
  4214. MUST BE CALLED WITH THE ASSOCIATED ADDRESS LOCK HELD!
  4215. Arguments:
  4216. Return Value:
  4217. --*/
  4218. {
  4219. PADSP_CONNOBJ pNextConn = NULL;
  4220. *pError = ATALK_FAILURE;
  4221. ASSERT(VALID_ADSPCO(pAdspConn));
  4222. for (; pAdspConn != NULL; pAdspConn = pAdspConn->adspco_pNextActive)
  4223. {
  4224. AtalkAdspConnReferenceByPtr(pAdspConn, pError);
  4225. if (ATALK_SUCCESS(*pError))
  4226. {
  4227. // Ok, this connection is referenced!
  4228. *ppAdspConnNext = pAdspConn;
  4229. break;
  4230. }
  4231. }
  4232. }
  4233. VOID
  4234. atalkAdspConnDeref(
  4235. IN PADSP_CONNOBJ pAdspConn
  4236. )
  4237. /*++
  4238. Routine Description:
  4239. Disconnect completion happens when the reference count goes from
  4240. 2->1 if the creation reference is not already removed. If the creation
  4241. reference is already removed, it will be done when the refcount goes
  4242. from 1->0.
  4243. Creation reference is never removed until cleanup completes.
  4244. Arguments:
  4245. Return Value:
  4246. --*/
  4247. {
  4248. BOOLEAN fEndProcessing = FALSE;
  4249. KIRQL OldIrql;
  4250. ASSERT(VALID_ADSPCO(pAdspConn));
  4251. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  4252. ASSERT(pAdspConn->adspco_RefCount > 0);
  4253. --pAdspConn->adspco_RefCount;
  4254. if (pAdspConn->adspco_RefCount > 1)
  4255. {
  4256. fEndProcessing = TRUE;
  4257. }
  4258. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  4259. if (fEndProcessing)
  4260. {
  4261. return;
  4262. }
  4263. else
  4264. {
  4265. ATALK_ERROR disconnectStatus;
  4266. PADSP_ADDROBJ pAdspAddr = pAdspConn->adspco_pAssocAddr;
  4267. BOOLEAN done = FALSE;
  4268. BOOLEAN disconnDone = FALSE;
  4269. BOOLEAN pendingRead = FALSE;
  4270. BOOLEAN pendingWrite= FALSE;
  4271. BOOLEAN stopping = FALSE;
  4272. GENERIC_COMPLETION disconnectInform = NULL;
  4273. PVOID disconnectInformCtx = NULL;
  4274. GENERIC_COMPLETION disconnectCompletion = NULL;
  4275. PVOID disconnectCtx = NULL;
  4276. PVOID cleanupCtx = NULL;
  4277. GENERIC_COMPLETION cleanupCompletion = NULL;
  4278. // We allow stopping phase to happen only after disconnecting is done.
  4279. // If disconnecting is not set and stopping is, it implies we are only
  4280. // in an associated state.
  4281. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  4282. stopping = (pAdspConn->adspco_Flags & ADSPCO_STOPPING) ? TRUE : FALSE;
  4283. if (pAdspConn->adspco_Flags & ADSPCO_DISCONNECTING)
  4284. {
  4285. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4286. ("atalkAdspConnDeref: Disconnect set for %lx\n", pAdspConn));
  4287. // Are we done disconnecting? Since cleanup wont complete until disc
  4288. // does, we don't have to worry about the creation ref having gone
  4289. // away.
  4290. if (pAdspConn->adspco_RefCount == 1)
  4291. {
  4292. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4293. ("atalkAdspConnDeref: Disconnect done (1) %lx\n", pAdspConn));
  4294. // Avoid multiple disconnect completions/close atp addresses
  4295. // Remember all the disconnect info before we release the lock
  4296. disconnectInform = pAdspConn->adspco_DisconnectInform;
  4297. disconnectInformCtx = pAdspConn->adspco_DisconnectInformCtx;
  4298. disconnectStatus = pAdspConn->adspco_DisconnectStatus;
  4299. disconnectCompletion = pAdspConn->adspco_DisconnectCompletion;
  4300. disconnectCtx = pAdspConn->adspco_DisconnectCtx;
  4301. // Reset all the be null, so next request doesnt get any
  4302. pAdspConn->adspco_DisconnectInform = NULL;
  4303. pAdspConn->adspco_DisconnectInformCtx = NULL;
  4304. pAdspConn->adspco_DisconnectCompletion = NULL;
  4305. pAdspConn->adspco_DisconnectCtx = NULL;
  4306. disconnDone = TRUE;
  4307. stopping = (pAdspConn->adspco_Flags & ADSPCO_STOPPING) ? TRUE : FALSE;
  4308. }
  4309. else
  4310. {
  4311. // Set stopping to false as disconnect is not done yet.
  4312. stopping = FALSE;
  4313. }
  4314. }
  4315. if (pAdspConn->adspco_RefCount == 0)
  4316. {
  4317. done = TRUE;
  4318. ASSERT(pAdspConn->adspco_Flags & ADSPCO_CLOSING);
  4319. }
  4320. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  4321. if (disconnDone)
  4322. {
  4323. // Remove from the active queue.
  4324. // Reset all relevent flags.
  4325. ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
  4326. ACQUIRE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  4327. pAdspConn->adspco_Flags &= ~(ADSPCO_LISTENING |
  4328. ADSPCO_CONNECTING |
  4329. ADSPCO_HALF_ACTIVE|
  4330. ADSPCO_ACTIVE |
  4331. ADSPCO_DISCONNECTING);
  4332. atalkAdspConnDeQueueActiveList(pAdspAddr, pAdspConn);
  4333. // if the address has been disassociated, time to unlink it.
  4334. if (!(pAdspConn->adspco_Flags & ADSPCO_ASSOCIATED))
  4335. {
  4336. pAdspConn->adspco_pAssocAddr = NULL;
  4337. }
  4338. RELEASE_SPIN_LOCK_DPC(&pAdspConn->adspco_Lock);
  4339. RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
  4340. // Call the disconnect completion routines.
  4341. if (*disconnectInform != NULL)
  4342. {
  4343. (*disconnectInform)(disconnectStatus, disconnectInformCtx);
  4344. }
  4345. if (*disconnectCompletion != NULL)
  4346. {
  4347. (*disconnectCompletion)(disconnectStatus, disconnectCtx);
  4348. }
  4349. }
  4350. if (stopping)
  4351. {
  4352. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  4353. if ((pAdspConn->adspco_Flags & ADSPCO_STOPPING) != 0)
  4354. {
  4355. BOOLEAN fDisassoc = FALSE;
  4356. // See if we do the cleanup irp completion.
  4357. if (pAdspConn->adspco_RefCount == 1)
  4358. {
  4359. cleanupCtx = pAdspConn->adspco_CleanupCtx;
  4360. cleanupCompletion = pAdspConn->adspco_CleanupComp;
  4361. pAdspConn->adspco_CleanupComp = NULL;
  4362. pAdspConn->adspco_Flags &= ~ADSPCO_STOPPING;
  4363. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4364. ("atalkAdspConnDeref: Cleanup on %lx.%lx\n", pAdspConn, cleanupCtx));
  4365. if ((pAdspConn->adspco_Flags & (ADSPCO_LISTENING |
  4366. ADSPCO_CONNECTING |
  4367. ADSPCO_ACTIVE)) == 0)
  4368. {
  4369. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4370. ("atalkAdspConnDeref: Stopping - do disassoc for %lx\n", pAdspConn));
  4371. fDisassoc = (pAdspConn->adspco_Flags & ADSPCO_ASSOCIATED) ? TRUE: FALSE;
  4372. }
  4373. }
  4374. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  4375. if (fDisassoc)
  4376. {
  4377. // Call the disassociate routine. This should just fail, if the
  4378. // connection is still active or any other state than just
  4379. // plain associated.
  4380. AtalkAdspDissociateAddress(pAdspConn);
  4381. }
  4382. }
  4383. else
  4384. {
  4385. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  4386. }
  4387. }
  4388. if (done)
  4389. {
  4390. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4391. ("atalkAdspConnDeref: Close done for %lx\n", pAdspConn));
  4392. // Call the close completion routines
  4393. ASSERT(*pAdspConn->adspco_CloseComp != NULL);
  4394. if (*pAdspConn->adspco_CloseComp != NULL)
  4395. {
  4396. (*pAdspConn->adspco_CloseComp )(ATALK_NO_ERROR,
  4397. pAdspConn->adspco_CloseCtx);
  4398. }
  4399. // Remove from the global list.
  4400. atalkAdspConnDeQueueGlobalList(pAdspConn);
  4401. // Free up the connection memory.
  4402. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4403. ("atalkAdspConnDeref: Freeing up connection %lx\n", pAdspConn));
  4404. AtalkUnlockAdspIfNecessary();
  4405. AtalkFreeMemory(pAdspConn);
  4406. }
  4407. if (*cleanupCompletion != NULL)
  4408. {
  4409. (*cleanupCompletion)(ATALK_NO_ERROR, cleanupCtx);
  4410. }
  4411. }
  4412. }
  4413. //
  4414. // ADSP BUFFER QUEUE MANAGEMENT ROUTINES
  4415. //
  4416. ULONG
  4417. atalkAdspMaxSendSize(
  4418. IN PADSP_CONNOBJ pAdspConn
  4419. )
  4420. /*++
  4421. Routine Description:
  4422. The answer is the remaining available (to fill) space in the retransmit
  4423. queue -- this includes data we're saving for possible retransmit as well
  4424. as data we haven't sent yet. Actually, this could go negative because
  4425. BufferQueueSize counts EOMs and sendQueueMax doesn't -- answer with zero
  4426. if this happens.
  4427. Arguments:
  4428. Return Value:
  4429. --*/
  4430. {
  4431. LONG sendSize;
  4432. sendSize = pAdspConn->adspco_SendQueueMax -
  4433. atalkAdspBufferQueueSize(&pAdspConn->adspco_SendQueue);
  4434. if (sendSize < 0)
  4435. {
  4436. sendSize = 0;
  4437. }
  4438. return ((ULONG)sendSize);
  4439. }
  4440. ULONG
  4441. atalkAdspMaxNextReadSize(
  4442. IN PBUFFER_QUEUE pQueue,
  4443. OUT PBOOLEAN pEom,
  4444. OUT PBUFFER_CHUNK * pBufferChunk
  4445. )
  4446. /*++
  4447. Routine Description:
  4448. Return the size of data in a buffer queue; upto the end of the
  4449. current chunk, or to the eom.
  4450. Arguments:
  4451. Return Value:
  4452. --*/
  4453. {
  4454. PBUFFER_CHUNK pCurrentChunk;
  4455. ULONG nextReadSize;
  4456. ULONG startIndex = pQueue->bq_StartIndex;
  4457. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4458. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4459. *pEom = FALSE;
  4460. // Walk the queue.
  4461. for (pCurrentChunk = pQueue->bq_Head;
  4462. pCurrentChunk != NULL;
  4463. pCurrentChunk = pCurrentChunk->bc_Next)
  4464. {
  4465. // Check for nothing in the current chunk
  4466. if (startIndex == (ULONG)(pCurrentChunk->bc_DataSize +
  4467. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM)))
  4468. {
  4469. startIndex = 0;
  4470. continue;
  4471. }
  4472. nextReadSize = pCurrentChunk->bc_DataSize - startIndex;
  4473. if (pCurrentChunk->bc_Flags & BC_EOM)
  4474. {
  4475. *pEom = TRUE;
  4476. }
  4477. *pBufferChunk = pCurrentChunk;
  4478. break;
  4479. }
  4480. // Return the size.
  4481. return nextReadSize;
  4482. }
  4483. ULONG
  4484. atalkAdspDescribeFromBufferQueue(
  4485. IN PBUFFER_QUEUE pQueue,
  4486. OUT PBOOLEAN pEom,
  4487. IN ULONG WindowSize,
  4488. OUT PBUFFER_CHUNK * ppBufferChunk,
  4489. OUT PBUFFER_DESC * ppBuffDesc
  4490. )
  4491. /*++
  4492. Routine Description:
  4493. In order to avoid pQueue (nextSendQueue) to go to null when all the data available
  4494. is being sent, we make it logically be at the end while still pointing to the
  4495. buffer chunk. This is the reason, we have all the datasize == (startindex + eom)
  4496. checks. This is where such a condition will be created.
  4497. NO! We let pQueue go to null when all the data is done, otherwise we will have
  4498. pointers to a buffer chunk that will be freed during discard, and we dont want to
  4499. make discard dependent upon the auxqueue.
  4500. Arguments:
  4501. Return Value:
  4502. --*/
  4503. {
  4504. PBUFFER_CHUNK pCurrentChunk;
  4505. PBUFFER_DESC pBuffDesc;
  4506. ULONG nextReadSize = 0;
  4507. ULONG startIndex = pQueue->bq_StartIndex;
  4508. *pEom = FALSE;
  4509. *ppBufferChunk = NULL;
  4510. *ppBuffDesc = NULL;
  4511. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4512. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4513. // Walk the queue.
  4514. for (pCurrentChunk = pQueue->bq_Head;
  4515. pCurrentChunk != NULL;
  4516. pCurrentChunk = pCurrentChunk->bc_Next)
  4517. {
  4518. // Check for nothing in the current chunk
  4519. if (startIndex == (ULONG)(pCurrentChunk->bc_DataSize +
  4520. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM)))
  4521. {
  4522. ASSERT(0);
  4523. startIndex = 0;
  4524. continue;
  4525. }
  4526. nextReadSize = pCurrentChunk->bc_DataSize - startIndex;
  4527. // Look at eom only if chunk is consumed.
  4528. *pEom = FALSE;
  4529. ASSERT(nextReadSize <= pCurrentChunk->bc_DataSize);
  4530. // Make sure dataSize is within bounds
  4531. if (nextReadSize > ADSP_MAX_DATA_SIZE)
  4532. {
  4533. nextReadSize = ADSP_MAX_DATA_SIZE;
  4534. }
  4535. if (nextReadSize > (ULONG)WindowSize)
  4536. {
  4537. nextReadSize = (ULONG)WindowSize;
  4538. }
  4539. if (nextReadSize > 0)
  4540. {
  4541. // First try to reference the buffer chunk. This should always succeed.
  4542. atalkAdspBufferChunkReference(pCurrentChunk);
  4543. // Create a descriptor for the data. The above reference goes away in a send
  4544. // complete.
  4545. pBuffDesc = AtalkDescribeBuffDesc((PBYTE)pCurrentChunk + sizeof(BUFFER_CHUNK) + startIndex,
  4546. NULL,
  4547. (USHORT)nextReadSize,
  4548. BD_CHAR_BUFFER);
  4549. *ppBufferChunk = pCurrentChunk;
  4550. *ppBuffDesc = pBuffDesc;
  4551. }
  4552. // Also update the queue for this data. Either we have consumed
  4553. // this chunk or we have just used a portion of it.
  4554. if ((nextReadSize + startIndex) == pCurrentChunk->bc_DataSize)
  4555. {
  4556. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4557. ("atalkAdspDescribeFromBufferQueue: Chunk consumed %d\n",
  4558. pCurrentChunk->bc_DataSize));
  4559. ASSERT(pQueue->bq_Head != NULL);
  4560. // Set EOM if chunk had one.
  4561. if (pCurrentChunk->bc_Flags & BC_EOM)
  4562. {
  4563. *pEom = TRUE;
  4564. }
  4565. if (pQueue->bq_Head == pQueue->bq_Tail)
  4566. {
  4567. ASSERT(pQueue->bq_Head->bc_Next == NULL);
  4568. pQueue->bq_Tail = pQueue->bq_Head->bc_Next;
  4569. ASSERT(pQueue->bq_Tail == NULL);
  4570. }
  4571. pQueue->bq_Head = pQueue->bq_Head->bc_Next;
  4572. pQueue->bq_StartIndex = (ULONG)0;
  4573. }
  4574. else
  4575. {
  4576. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4577. ("atalkAdspDescribeFromBufferQueue: Chunk not consumed %d.%d\n",
  4578. pCurrentChunk->bc_DataSize, nextReadSize+startIndex));
  4579. // Just set the start index
  4580. pQueue->bq_StartIndex += (ULONG)nextReadSize;
  4581. }
  4582. break;
  4583. }
  4584. // Return the size.
  4585. return nextReadSize;
  4586. }
  4587. ULONG
  4588. atalkAdspBufferQueueSize(
  4589. IN PBUFFER_QUEUE pQueue
  4590. )
  4591. /*++
  4592. Routine Description:
  4593. Return the total size of a buffer queue; each EOM counts as a single
  4594. byte.
  4595. Arguments:
  4596. Return Value:
  4597. --*/
  4598. {
  4599. PBUFFER_CHUNK pCurrentChunk;
  4600. ULONG startIndex;
  4601. ULONG queueSize;
  4602. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4603. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4604. // Walk the queue.
  4605. for (queueSize = 0, startIndex = pQueue->bq_StartIndex, pCurrentChunk = pQueue->bq_Head;
  4606. pCurrentChunk != NULL;
  4607. pCurrentChunk = pCurrentChunk->bc_Next)
  4608. {
  4609. // Check for nothing in the current chunk.
  4610. if (startIndex == (ULONG)(pCurrentChunk->bc_DataSize +
  4611. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM)))
  4612. {
  4613. startIndex = 0;
  4614. continue;
  4615. }
  4616. queueSize += ( pCurrentChunk->bc_DataSize -
  4617. startIndex +
  4618. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM));
  4619. // StartIndex only counts in first chunk
  4620. startIndex = 0;
  4621. }
  4622. // Return the size.
  4623. return queueSize;
  4624. }
  4625. ULONG
  4626. atalkAdspMessageSize(
  4627. IN PBUFFER_QUEUE pQueue,
  4628. OUT PBOOLEAN pEom
  4629. )
  4630. /*++
  4631. Routine Description:
  4632. Return the total size of the data in the buffer queue, stopping at eom
  4633. or end of data. EOM is not part of the count.
  4634. Arguments:
  4635. Return Value:
  4636. --*/
  4637. {
  4638. PBUFFER_CHUNK pCurrentChunk;
  4639. ULONG msgSize = 0;
  4640. ULONG startIndex = pQueue->bq_StartIndex;
  4641. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4642. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4643. *pEom = FALSE;
  4644. // Walk the queue.
  4645. for (pCurrentChunk = pQueue->bq_Head;
  4646. pCurrentChunk != NULL;
  4647. pCurrentChunk = pCurrentChunk->bc_Next)
  4648. {
  4649. // Check for nothing in the current chunk.
  4650. if (startIndex == (ULONG)(pCurrentChunk->bc_DataSize +
  4651. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM)))
  4652. {
  4653. startIndex = 0;
  4654. continue;
  4655. }
  4656. msgSize += (pCurrentChunk->bc_DataSize - startIndex);
  4657. if (pCurrentChunk->bc_Flags & BC_EOM)
  4658. {
  4659. *pEom = TRUE;
  4660. break;
  4661. }
  4662. // StartIndex only counts in first chunk
  4663. startIndex = 0;
  4664. }
  4665. // Return the size.
  4666. return msgSize;
  4667. }
  4668. PBUFFER_CHUNK
  4669. atalkAdspAllocCopyChunk(
  4670. IN PVOID pWriteBuf,
  4671. IN USHORT WriteBufLen,
  4672. IN BOOLEAN Eom,
  4673. IN BOOLEAN IsCharBuffer
  4674. )
  4675. /*++
  4676. Routine Description:
  4677. Arguments:
  4678. Return Value:
  4679. --*/
  4680. {
  4681. PBUFFER_CHUNK pChunk;
  4682. PBYTE pData;
  4683. NTSTATUS status;
  4684. ULONG bytesCopied;
  4685. if ((pChunk = (PBUFFER_CHUNK)AtalkAllocMemory(sizeof(BUFFER_CHUNK) + WriteBufLen)) != NULL)
  4686. {
  4687. pChunk->bc_DataSize = WriteBufLen;
  4688. pChunk->bc_Flags = (Eom ? BC_EOM : 0);
  4689. pChunk->bc_Next = NULL;
  4690. pChunk->bc_RefCount = 1; // Creation ref count
  4691. INITIALIZE_SPIN_LOCK(&pChunk->bc_Lock);
  4692. // Copy the data over if its greater than zero
  4693. if (WriteBufLen > 0)
  4694. {
  4695. pData = (PBYTE)pChunk + sizeof(BUFFER_CHUNK);
  4696. if (IsCharBuffer)
  4697. {
  4698. RtlCopyMemory(pData,
  4699. (PBYTE)pWriteBuf,
  4700. WriteBufLen);
  4701. }
  4702. else
  4703. {
  4704. status = TdiCopyMdlToBuffer((PMDL)pWriteBuf,
  4705. 0,
  4706. pData,
  4707. 0,
  4708. WriteBufLen,
  4709. &bytesCopied);
  4710. ASSERT(!NT_ERROR(status) && (bytesCopied == (ULONG)WriteBufLen));
  4711. }
  4712. }
  4713. }
  4714. return pChunk;
  4715. }
  4716. PBYTE
  4717. atalkAdspGetLookahead(
  4718. IN PBUFFER_QUEUE pQueue,
  4719. OUT PULONG pLookaheadSize
  4720. )
  4721. /*++
  4722. Routine Description:
  4723. Arguments:
  4724. Return Value:
  4725. --*/
  4726. {
  4727. PBUFFER_CHUNK pCurrentChunk;
  4728. ULONG startIndex = pQueue->bq_StartIndex;
  4729. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4730. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4731. pCurrentChunk = pQueue->bq_Head;
  4732. if (pCurrentChunk != NULL)
  4733. {
  4734. // Do we need to go past the current chunk?
  4735. if (startIndex == (ULONG)(pCurrentChunk->bc_DataSize +
  4736. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM)))
  4737. {
  4738. pCurrentChunk = pCurrentChunk->bc_Next;
  4739. startIndex = 0;
  4740. }
  4741. }
  4742. ASSERT(pCurrentChunk != NULL);
  4743. if (pCurrentChunk == NULL)
  4744. {
  4745. KeBugCheck(0);
  4746. }
  4747. *pLookaheadSize = pCurrentChunk->bc_DataSize - startIndex;
  4748. return((*pLookaheadSize == 0) ?
  4749. NULL :
  4750. (PBYTE)pCurrentChunk + sizeof(BUFFER_CHUNK) + startIndex);
  4751. }
  4752. VOID
  4753. atalkAdspAddToBufferQueue(
  4754. IN OUT PBUFFER_QUEUE pQueue,
  4755. IN PBUFFER_CHUNK pChunk,
  4756. IN OUT PBUFFER_QUEUE pAuxQueue OPTIONAL
  4757. )
  4758. /*++
  4759. Routine Description:
  4760. !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
  4761. Arguments:
  4762. Return Value:
  4763. --*/
  4764. {
  4765. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4766. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4767. if (pQueue->bq_Head != NULL)
  4768. {
  4769. // Add the chunk to the end of the queue
  4770. ASSERT(pQueue->bq_Tail != NULL);
  4771. pQueue->bq_Tail->bc_Next = pChunk;
  4772. pQueue->bq_Tail = pChunk;
  4773. ASSERT(pChunk->bc_Next == NULL);
  4774. // The auxiliary queue is the nextsend queue, which can go to null
  4775. // if we have sent all the data. If that is the case, we need to
  4776. // reset the head also.
  4777. if (ARGUMENT_PRESENT(pAuxQueue))
  4778. {
  4779. if (pAuxQueue->bq_Head == NULL)
  4780. {
  4781. pAuxQueue->bq_Head = pChunk;
  4782. }
  4783. pAuxQueue->bq_Tail = pChunk;
  4784. }
  4785. }
  4786. else
  4787. {
  4788. pQueue->bq_Head = pQueue->bq_Tail = pChunk;
  4789. pQueue->bq_StartIndex = (ULONG)0;
  4790. if (ARGUMENT_PRESENT(pAuxQueue))
  4791. {
  4792. // Initialize the next send queue only if this is a send queue
  4793. pAuxQueue->bq_Head = pAuxQueue->bq_Tail = pChunk;
  4794. pAuxQueue->bq_StartIndex= (ULONG)0;
  4795. }
  4796. }
  4797. }
  4798. ULONG
  4799. atalkAdspReadFromBufferQueue(
  4800. IN PBUFFER_QUEUE pQueue,
  4801. IN ULONG ReadFlags,
  4802. OUT PAMDL pReadBuf,
  4803. IN OUT PUSHORT pReadLen,
  4804. OUT PBOOLEAN pEom
  4805. )
  4806. /*++
  4807. Routine Description:
  4808. Arguments:
  4809. Return Value:
  4810. --*/
  4811. {
  4812. PBUFFER_CHUNK pCurrentChunk;
  4813. ULONG bytesRead, copySize, dataIndex, dataSize, lastReadIndex;
  4814. NTSTATUS status;
  4815. LONG startIndex = pQueue->bq_StartIndex;
  4816. ATALK_ERROR error = ATALK_NO_ERROR;
  4817. ULONG readSize = 0; // size counting eom
  4818. ASSERT(((pQueue->bq_Head == NULL) && (pQueue->bq_Tail == NULL)) ||
  4819. ((pQueue->bq_Head != NULL) && (pQueue->bq_Tail != NULL)));
  4820. *pEom = FALSE;
  4821. readSize = 0;
  4822. pCurrentChunk = pQueue->bq_Head;
  4823. if ((pCurrentChunk == NULL) ||
  4824. ((pCurrentChunk->bc_Next == NULL) &&
  4825. ((ULONG)startIndex == pCurrentChunk->bc_DataSize +
  4826. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM))))
  4827. {
  4828. *pReadLen = 0;
  4829. return 0;
  4830. }
  4831. dataIndex = 0;
  4832. dataSize = *pReadLen;
  4833. // Copy data until we exhaust src/dest buffers or hit an eom
  4834. for (;
  4835. pCurrentChunk != NULL;
  4836. pCurrentChunk = pCurrentChunk->bc_Next)
  4837. {
  4838. if ((ULONG)startIndex == pCurrentChunk->bc_DataSize +
  4839. BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM))
  4840. {
  4841. ASSERT(0);
  4842. startIndex = 0;
  4843. continue;
  4844. }
  4845. copySize = MIN((ULONG)(pCurrentChunk->bc_DataSize - startIndex), dataSize);
  4846. if (copySize > 0)
  4847. {
  4848. status = TdiCopyBufferToMdl((PBYTE)pCurrentChunk +
  4849. sizeof(BUFFER_CHUNK) +
  4850. startIndex,
  4851. 0,
  4852. copySize,
  4853. pReadBuf,
  4854. dataIndex,
  4855. &bytesRead);
  4856. ASSERT(NT_SUCCESS(status) && (copySize == bytesRead));
  4857. }
  4858. dataIndex += copySize;
  4859. readSize += copySize;
  4860. dataSize -= copySize;
  4861. lastReadIndex = startIndex + copySize;
  4862. // Check for terminating conditions
  4863. startIndex = 0;
  4864. // Check EOM only if chunk consumed.
  4865. if ((lastReadIndex == pCurrentChunk->bc_DataSize) &&
  4866. (pCurrentChunk->bc_Flags & BC_EOM))
  4867. {
  4868. readSize += 1;
  4869. *pEom = TRUE;
  4870. break;
  4871. }
  4872. if (dataSize == 0) // Is the user buffer full?
  4873. {
  4874. break;
  4875. }
  4876. }
  4877. *pReadLen = (USHORT)dataIndex;
  4878. // Free any chunks that we are done with, only if this was not a peek request.
  4879. if ((ReadFlags & TDI_RECEIVE_PEEK) == 0)
  4880. {
  4881. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4882. ("atalkAdspReadFromBufferQueue: Discarding data %lx\n", dataIndex));
  4883. atalkAdspDiscardFromBufferQueue(pQueue,
  4884. readSize,
  4885. NULL,
  4886. ATALK_NO_ERROR,
  4887. NULL);
  4888. }
  4889. return dataIndex;
  4890. }
  4891. BOOLEAN
  4892. atalkAdspDiscardFromBufferQueue(
  4893. IN PBUFFER_QUEUE pQueue,
  4894. IN ULONG DataSize,
  4895. OUT PBUFFER_QUEUE pAuxQueue,
  4896. IN ATALK_ERROR Error,
  4897. IN PADSP_CONNOBJ pAdspConn OPTIONAL // Required for send queue
  4898. )
  4899. /*++
  4900. Routine Description:
  4901. Arguments:
  4902. Return Value:
  4903. --*/
  4904. {
  4905. PBUFFER_CHUNK pCurrentChunk, pNextChunk;
  4906. ULONG chunkSize, startIndex = pQueue->bq_StartIndex;
  4907. // BUBBUG: error checks
  4908. // Walk along the queue discarding the data we have already read
  4909. for (pCurrentChunk = pQueue->bq_Head, pNextChunk = NULL;
  4910. pCurrentChunk != NULL;
  4911. pCurrentChunk = pNextChunk)
  4912. {
  4913. pNextChunk = pCurrentChunk->bc_Next;
  4914. chunkSize = pCurrentChunk->bc_DataSize -
  4915. startIndex + BYTECOUNT(pCurrentChunk->bc_Flags & BC_EOM);
  4916. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  4917. ("atalkAdspDiscardFromBufferQueue: Discarding %ld.%ld\n", DataSize, chunkSize));
  4918. // If we finished discarding but there is still some data left in the
  4919. // current chunk, just reset the start index.
  4920. if (DataSize < chunkSize)
  4921. {
  4922. // Already done: pQueue->bq_Head = pCurrentChunk;
  4923. pQueue->bq_StartIndex = startIndex + DataSize;
  4924. ASSERT((pQueue->bq_Head != pQueue->bq_Tail) ||
  4925. (pCurrentChunk->bc_Next == NULL));
  4926. return TRUE;
  4927. }
  4928. // Otherwise, we have discarded a whole chunk
  4929. if ((pAuxQueue != NULL) &&
  4930. (pAuxQueue->bq_Head == pCurrentChunk) &&
  4931. ((pAuxQueue->bq_Head->bc_Next != NULL) ||
  4932. (pAuxQueue->bq_StartIndex <
  4933. (pAuxQueue->bq_Head->bc_DataSize +
  4934. (ULONG)BYTECOUNT(pAuxQueue->bq_Head->bc_Flags & BC_EOM)))))
  4935. {
  4936. ASSERT(0);
  4937. pAuxQueue->bq_Head = pAuxQueue->bq_Tail = NULL;
  4938. pAuxQueue->bq_StartIndex = (ULONG)0;
  4939. }
  4940. // If SEND chunk, set error for the send to be success
  4941. if (pCurrentChunk->bc_Flags & BC_SEND)
  4942. {
  4943. pCurrentChunk->bc_WriteError = Error;
  4944. ASSERT(pAdspConn != NULL);
  4945. }
  4946. //
  4947. // make our head point to the next guy since this chunk is going away.
  4948. //
  4949. pQueue->bq_Head = pNextChunk;
  4950. pQueue->bq_StartIndex = 0;
  4951. if (pQueue->bq_Tail == pCurrentChunk)
  4952. {
  4953. pQueue->bq_Tail = NULL;
  4954. }
  4955. // Deref for creation.
  4956. atalkAdspBufferChunkDereference(pCurrentChunk,
  4957. TRUE,
  4958. pAdspConn);
  4959. // Move on to the next chunk
  4960. DataSize -= chunkSize;
  4961. startIndex = 0;
  4962. }
  4963. // If we are here, then the whole queue has been discarded, mark
  4964. // it as empty
  4965. ASSERT(DataSize == 0);
  4966. //pQueue->bq_Head = pQueue->bq_Tail = NULL;
  4967. //pQueue->bq_StartIndex = 0;
  4968. //
  4969. // if the last chunk gets freed above, we release the spinlock to complete the
  4970. // irp associated with the chunk and then grab it again. It's possible to get
  4971. // a new send in that window, so bq_head may not necessarily be NULL at this
  4972. // point (in fact, bug #16660 turned out to be exactly this!!)
  4973. //
  4974. if (pQueue->bq_Head == NULL)
  4975. {
  4976. ASSERT(pQueue->bq_Tail == NULL);
  4977. if (pAuxQueue != NULL)
  4978. {
  4979. pAuxQueue->bq_Head = pAuxQueue->bq_Tail = NULL;
  4980. pAuxQueue->bq_StartIndex = (LONG)0;
  4981. }
  4982. }
  4983. return TRUE;
  4984. }
  4985. VOID
  4986. atalkAdspBufferChunkReference(
  4987. IN PBUFFER_CHUNK pBufferChunk
  4988. )
  4989. /*++
  4990. Routine Description:
  4991. Arguments:
  4992. Return Value:
  4993. --*/
  4994. {
  4995. KIRQL OldIrql;
  4996. ACQUIRE_SPIN_LOCK(&pBufferChunk->bc_Lock, &OldIrql);
  4997. if ((pBufferChunk->bc_Flags & BC_CLOSING) == 0)
  4998. {
  4999. pBufferChunk->bc_RefCount++;
  5000. }
  5001. else
  5002. {
  5003. // Should never be trying to reference this when closing. The retransmit
  5004. // timer should have been cancelled.
  5005. KeBugCheck(0);
  5006. }
  5007. RELEASE_SPIN_LOCK(&pBufferChunk->bc_Lock, OldIrql);
  5008. }
  5009. VOID
  5010. atalkAdspBufferChunkDereference(
  5011. IN PBUFFER_CHUNK pBufferChunk,
  5012. IN BOOLEAN CreationDeref,
  5013. IN PADSP_CONNOBJ pAdspConn OPTIONAL // Required for send chunk
  5014. // If spinlock held
  5015. )
  5016. /*++
  5017. Routine Description:
  5018. Arguments:
  5019. Return Value:
  5020. --*/
  5021. {
  5022. BOOLEAN done = FALSE;
  5023. BOOLEAN sendChunk = FALSE;
  5024. KIRQL OldIrql;
  5025. ACQUIRE_SPIN_LOCK(&pBufferChunk->bc_Lock, &OldIrql);
  5026. if (!CreationDeref ||
  5027. ((pBufferChunk->bc_Flags & BC_CLOSING) == 0))
  5028. {
  5029. if (CreationDeref)
  5030. {
  5031. pBufferChunk->bc_Flags |= BC_CLOSING;
  5032. }
  5033. if (--pBufferChunk->bc_RefCount == 0)
  5034. {
  5035. ASSERT(pBufferChunk->bc_Flags & BC_CLOSING);
  5036. done = TRUE;
  5037. sendChunk = (pBufferChunk->bc_Flags & BC_SEND) ? TRUE : FALSE;
  5038. }
  5039. }
  5040. RELEASE_SPIN_LOCK(&pBufferChunk->bc_Lock, OldIrql);
  5041. if (done)
  5042. {
  5043. // Call send completion if this is a send buffer chunk
  5044. if (sendChunk)
  5045. {
  5046. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5047. ("atalkChunkDereference: Completing send %lx. %lx - %d.%d\n",
  5048. pAdspConn, pBufferChunk->bc_WriteCtx,
  5049. pBufferChunk->bc_DataSize, pBufferChunk->bc_WriteError));
  5050. if (pAdspConn != NULL)
  5051. {
  5052. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5053. ("atalkChunkDereference: Completing send %lx.%lx\n",
  5054. pAdspConn, pBufferChunk->bc_WriteCtx));
  5055. // Release connection lock
  5056. RELEASE_SPIN_LOCK(&pAdspConn->adspco_Lock, OldIrql);
  5057. }
  5058. // Call the completion routine. We complete with no error, but
  5059. // need to return pending.
  5060. ASSERT((*pBufferChunk->bc_WriteCompletion) != NULL);
  5061. (*pBufferChunk->bc_WriteCompletion)(pBufferChunk->bc_WriteError,
  5062. pBufferChunk->bc_WriteBuf,
  5063. pBufferChunk->bc_DataSize,
  5064. pBufferChunk->bc_WriteCtx);
  5065. if (pAdspConn != NULL)
  5066. {
  5067. ACQUIRE_SPIN_LOCK(&pAdspConn->adspco_Lock, &OldIrql);
  5068. }
  5069. }
  5070. // This better not be part of the queues at this point, we should
  5071. // just be able to free it up. The idea is that if a particular
  5072. // buffer descriptor has its creation reference removed, its only
  5073. // because the data is being discarded or the connection is shutting
  5074. // down, in both cases, the data previous to this must be also being
  5075. // discarded and the buffer queue pointers will be set to the chunks
  5076. // following the ones being discarded. If this wont be true, walk the
  5077. // list (need more info coming in) and unlink this chunk before freeing
  5078. // it.
  5079. AtalkFreeMemory(pBufferChunk);
  5080. }
  5081. }
  5082. //
  5083. // ADSP UTILITY ROUTINES
  5084. //
  5085. VOID
  5086. atalkAdspDecodeHeader(
  5087. IN PBYTE Datagram,
  5088. OUT PUSHORT RemoteConnId,
  5089. OUT PULONG FirstByteSeq,
  5090. OUT PULONG NextRecvSeq,
  5091. OUT PLONG Window,
  5092. OUT PBYTE Descriptor
  5093. )
  5094. /*++
  5095. Routine Description:
  5096. Arguments:
  5097. Return Value:
  5098. --*/
  5099. {
  5100. GETSHORT2SHORT(RemoteConnId, Datagram + ADSP_SRC_CONNID_OFF);
  5101. GETDWORD2DWORD(FirstByteSeq, Datagram + ADSP_FIRST_BYTE_SEQNUM_OFF);
  5102. GETDWORD2DWORD(NextRecvSeq, Datagram + ADSP_NEXT_RX_BYTESEQNUM_OFF);
  5103. GETSHORT2DWORD(Window, Datagram + ADSP_RX_WINDOW_SIZE_OFF);
  5104. // Set the descriptor
  5105. *Descriptor = Datagram[ADSP_DESCRIPTOR_OFF];
  5106. }
  5107. LOCAL USHORT
  5108. atalkAdspGetNextConnId(
  5109. IN PADSP_ADDROBJ pAdspAddr,
  5110. OUT PATALK_ERROR pError
  5111. )
  5112. /*++
  5113. Routine Description:
  5114. CALLED WITH THE ADDRESS SPIN LOCK HELD!
  5115. Arguments:
  5116. Return Value:
  5117. --*/
  5118. {
  5119. PADSP_CONNOBJ pAdspConn;
  5120. USHORT i;
  5121. USHORT startConnId, connId;
  5122. ATALK_ERROR error = ATALK_NO_ERROR;
  5123. startConnId = connId = ++pAdspAddr->adspao_NextConnId;
  5124. while (TRUE)
  5125. {
  5126. for (i = 0; i < ADSP_CONN_HASH_SIZE; i++)
  5127. {
  5128. for (pAdspConn = pAdspAddr->adspao_pActiveHash[i];
  5129. ((pAdspConn != NULL) && (pAdspConn->adspco_LocalConnId != connId));
  5130. pAdspConn = pAdspConn->adspco_pNextActive);
  5131. if (pAdspConn != NULL)
  5132. break;
  5133. }
  5134. if (pAdspConn == NULL)
  5135. {
  5136. break;
  5137. }
  5138. else
  5139. {
  5140. if (connId == (startConnId - 1))
  5141. {
  5142. ASSERT(0);
  5143. // We wrapped around and there are no more conn ids.
  5144. error = ATALK_RESR_MEM;
  5145. break;
  5146. }
  5147. connId++;
  5148. }
  5149. }
  5150. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5151. ("atalkAdspGetNextConnId: ConnId %lx for %lx\n", connId, pAdspAddr));
  5152. *pError = error;
  5153. return(ATALK_SUCCESS(error) ? connId : 0);
  5154. }
  5155. LOCAL BOOLEAN
  5156. atalkAdspConnDeQueueAssocList(
  5157. IN PADSP_ADDROBJ pAdspAddr,
  5158. IN PADSP_CONNOBJ pAdspConn
  5159. )
  5160. /*++
  5161. Routine Description:
  5162. Arguments:
  5163. Return Value:
  5164. --*/
  5165. {
  5166. PADSP_CONNOBJ pAdspRemConn, *ppAdspRemConn;
  5167. BOOLEAN removed = FALSE;
  5168. for (ppAdspRemConn = &pAdspAddr->adspao_pAssocConn;
  5169. ((pAdspRemConn = *ppAdspRemConn) != NULL); )
  5170. {
  5171. if (pAdspRemConn == pAdspConn)
  5172. {
  5173. removed = TRUE;
  5174. *ppAdspRemConn = pAdspRemConn->adspco_pNextAssoc;
  5175. break;
  5176. }
  5177. else
  5178. {
  5179. ppAdspRemConn = &pAdspRemConn->adspco_pNextAssoc;
  5180. }
  5181. }
  5182. return removed;
  5183. }
  5184. LOCAL BOOLEAN
  5185. atalkAdspConnDeQueueConnectList(
  5186. IN PADSP_ADDROBJ pAdspAddr,
  5187. IN PADSP_CONNOBJ pAdspConn
  5188. )
  5189. /*++
  5190. Routine Description:
  5191. Arguments:
  5192. Return Value:
  5193. --*/
  5194. {
  5195. PADSP_CONNOBJ pAdspRemConn, *ppAdspRemConn;
  5196. BOOLEAN removed = FALSE;
  5197. ASSERT(pAdspAddr->adspao_Flags & ADSPAO_CONNECT);
  5198. for (ppAdspRemConn = &pAdspAddr->adspao_pConnectConn;
  5199. ((pAdspRemConn = *ppAdspRemConn) != NULL); )
  5200. {
  5201. if (pAdspRemConn == pAdspConn)
  5202. {
  5203. removed = TRUE;
  5204. *ppAdspRemConn = pAdspRemConn->adspco_pNextConnect;
  5205. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5206. ("atalkAdspConnDeQueueConnectList: Removed connect conn %lx\n", pAdspConn));
  5207. break;
  5208. }
  5209. else
  5210. {
  5211. ppAdspRemConn = &pAdspRemConn->adspco_pNextConnect;
  5212. }
  5213. }
  5214. return removed;
  5215. }
  5216. LOCAL BOOLEAN
  5217. atalkAdspConnDeQueueListenList(
  5218. IN PADSP_ADDROBJ pAdspAddr,
  5219. IN PADSP_CONNOBJ pAdspConn
  5220. )
  5221. /*++
  5222. Routine Description:
  5223. Arguments:
  5224. Return Value:
  5225. --*/
  5226. {
  5227. PADSP_CONNOBJ pAdspRemConn, *ppAdspRemConn;
  5228. BOOLEAN removed = FALSE;
  5229. ASSERT(pAdspAddr->adspao_Flags & ADSPAO_LISTENER);
  5230. for (ppAdspRemConn = &pAdspAddr->adspao_pListenConn;
  5231. ((pAdspRemConn = *ppAdspRemConn) != NULL); )
  5232. {
  5233. if (pAdspRemConn == pAdspConn)
  5234. {
  5235. removed = TRUE;
  5236. *ppAdspRemConn = pAdspRemConn->adspco_pNextListen;
  5237. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5238. ("atalkAdspConnDeQueueListenList: Removed listen conn %lx\n", pAdspConn));
  5239. }
  5240. else
  5241. {
  5242. ppAdspRemConn = &pAdspRemConn->adspco_pNextListen;
  5243. }
  5244. }
  5245. return removed;
  5246. }
  5247. LOCAL BOOLEAN
  5248. atalkAdspConnDeQueueActiveList(
  5249. IN PADSP_ADDROBJ pAdspAddr,
  5250. IN PADSP_CONNOBJ pAdspConn
  5251. )
  5252. /*++
  5253. Routine Description:
  5254. Arguments:
  5255. Return Value:
  5256. --*/
  5257. {
  5258. PADSP_CONNOBJ pAdspRemConn, *ppAdspRemConn;
  5259. ULONG index;
  5260. BOOLEAN removed = FALSE;
  5261. index = HASH_ID_SRCADDR(
  5262. pAdspConn->adspco_RemoteConnId,
  5263. &pAdspConn->adspco_RemoteAddr);
  5264. index %= ADSP_CONN_HASH_SIZE;
  5265. for (ppAdspRemConn = &pAdspAddr->adspao_pActiveHash[index];
  5266. ((pAdspRemConn = *ppAdspRemConn) != NULL); )
  5267. {
  5268. if (pAdspRemConn == pAdspConn)
  5269. {
  5270. removed = TRUE;
  5271. *ppAdspRemConn = pAdspRemConn->adspco_pNextActive;
  5272. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5273. ("atalkAdspConnDeQueueActiveList: Removed active conn %lx\n", pAdspConn));
  5274. break;
  5275. }
  5276. else
  5277. {
  5278. ppAdspRemConn = &pAdspRemConn->adspco_pNextActive;
  5279. }
  5280. }
  5281. return removed;
  5282. }
  5283. LOCAL VOID
  5284. atalkAdspAddrQueueGlobalList(
  5285. IN PADSP_ADDROBJ pAdspAddr
  5286. )
  5287. /*++
  5288. Routine Description:
  5289. Arguments:
  5290. Return Value:
  5291. --*/
  5292. {
  5293. KIRQL OldIrql;
  5294. ACQUIRE_SPIN_LOCK(&atalkAdspLock, &OldIrql);
  5295. pAdspAddr->adspao_pNextGlobal = atalkAdspAddrList;
  5296. atalkAdspAddrList = pAdspAddr;
  5297. RELEASE_SPIN_LOCK(&atalkAdspLock, OldIrql);
  5298. }
  5299. LOCAL VOID
  5300. atalkAdspAddrDeQueueGlobalList(
  5301. IN PADSP_ADDROBJ pAdspAddr
  5302. )
  5303. /*++
  5304. Routine Description:
  5305. Arguments:
  5306. Return Value:
  5307. --*/
  5308. {
  5309. KIRQL OldIrql;
  5310. PADSP_ADDROBJ pAdspRemAddr, *ppAdspRemAddr;
  5311. ACQUIRE_SPIN_LOCK(&atalkAdspLock, &OldIrql);
  5312. for (ppAdspRemAddr = &atalkAdspAddrList;
  5313. ((pAdspRemAddr = *ppAdspRemAddr) != NULL); )
  5314. {
  5315. if (pAdspRemAddr == pAdspAddr)
  5316. {
  5317. *ppAdspRemAddr = pAdspRemAddr->adspao_pNextGlobal;
  5318. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5319. ("atalkAdspAddrDeQueueGlobalList: Removed global conn %lx\n",pAdspAddr));
  5320. break;
  5321. }
  5322. else
  5323. {
  5324. ppAdspRemAddr = &pAdspRemAddr->adspao_pNextGlobal;
  5325. }
  5326. }
  5327. RELEASE_SPIN_LOCK(&atalkAdspLock, OldIrql);
  5328. }
  5329. LOCAL VOID
  5330. atalkAdspConnDeQueueGlobalList(
  5331. IN PADSP_CONNOBJ pAdspConn
  5332. )
  5333. /*++
  5334. Routine Description:
  5335. Arguments:
  5336. Return Value:
  5337. --*/
  5338. {
  5339. KIRQL OldIrql;
  5340. PADSP_CONNOBJ pAdspRemConn, *ppAdspRemConn;
  5341. ACQUIRE_SPIN_LOCK(&atalkAdspLock, &OldIrql);
  5342. for (ppAdspRemConn = &atalkAdspConnList;
  5343. ((pAdspRemConn = *ppAdspRemConn) != NULL); )
  5344. {
  5345. if (pAdspRemConn == pAdspConn)
  5346. {
  5347. *ppAdspRemConn = pAdspRemConn->adspco_pNextGlobal;
  5348. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5349. ("atalkAdspConnDeQueueGlobalList: Removed global conn %lx\n", pAdspConn));
  5350. break;
  5351. }
  5352. else
  5353. {
  5354. ppAdspRemConn = &pAdspRemConn->adspco_pNextGlobal;
  5355. }
  5356. }
  5357. RELEASE_SPIN_LOCK(&atalkAdspLock, OldIrql);
  5358. }
  5359. LOCAL BOOLEAN
  5360. atalkAdspAddrDeQueueOpenReq(
  5361. IN PADSP_ADDROBJ pAdspAddr,
  5362. IN USHORT RemoteConnId,
  5363. IN PATALK_ADDR pSrcAddr,
  5364. OUT PADSP_OPEN_REQ *ppAdspOpenReq
  5365. )
  5366. /*++
  5367. Routine Description:
  5368. Arguments:
  5369. Return Value:
  5370. --*/
  5371. {
  5372. PADSP_OPEN_REQ pOpenReq, *ppOpenReq;
  5373. BOOLEAN removed = FALSE;
  5374. for (ppOpenReq = &pAdspAddr->adspao_OpenReq;
  5375. ((pOpenReq = *ppOpenReq) != NULL); )
  5376. {
  5377. if ((pOpenReq->or_RemoteConnId == RemoteConnId) &&
  5378. (ATALK_ADDRS_EQUAL(&pOpenReq->or_RemoteAddr, pSrcAddr)))
  5379. {
  5380. removed = TRUE;
  5381. *ppOpenReq = pOpenReq->or_Next;
  5382. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5383. ("atalkAdspAddrDeQueueOpenReq: Removed OpenReq %lx\n", pOpenReq));
  5384. break;
  5385. }
  5386. else
  5387. {
  5388. ppOpenReq = &pOpenReq->or_Next;
  5389. }
  5390. }
  5391. *ppAdspOpenReq = NULL;
  5392. if (removed)
  5393. {
  5394. *ppAdspOpenReq = pOpenReq;
  5395. }
  5396. return removed;
  5397. }
  5398. LOCAL BOOLEAN
  5399. atalkAdspIsDuplicateOpenReq(
  5400. IN PADSP_ADDROBJ pAdspAddr,
  5401. IN USHORT RemoteConnId,
  5402. IN PATALK_ADDR pSrcAddr
  5403. )
  5404. /*++
  5405. Routine Description:
  5406. !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
  5407. Arguments:
  5408. Return Value:
  5409. --*/
  5410. {
  5411. PADSP_OPEN_REQ pOpenReqChk;
  5412. BOOLEAN found = FALSE;
  5413. for (pOpenReqChk = pAdspAddr->adspao_OpenReq;
  5414. pOpenReqChk != NULL;
  5415. pOpenReqChk = pOpenReqChk->or_Next)
  5416. {
  5417. if ((pOpenReqChk->or_RemoteConnId == RemoteConnId) &&
  5418. (ATALK_ADDRS_EQUAL(&pOpenReqChk->or_RemoteAddr, pSrcAddr)))
  5419. {
  5420. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5421. ("atalkAdspIsDuplicateOpenReq: Found\n"));
  5422. found = TRUE;
  5423. break;
  5424. }
  5425. }
  5426. return found;
  5427. }
  5428. LOCAL VOID
  5429. atalkAdspGenericComplete(
  5430. IN ATALK_ERROR ErrorCode,
  5431. IN PIRP pIrp
  5432. )
  5433. {
  5434. DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
  5435. ("atalkTdiGenericComplete: Completing %lx with %lx\n",
  5436. pIrp, AtalkErrorToNtStatus(ErrorCode)));
  5437. ASSERT (ErrorCode != ATALK_PENDING);
  5438. TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
  5439. }
  5440. VOID
  5441. atalkAdspConnFindInConnect(
  5442. IN PADSP_ADDROBJ pAdspAddr,
  5443. IN USHORT DestConnId,
  5444. IN PATALK_ADDR pRemoteAddr,
  5445. OUT PADSP_CONNOBJ * ppAdspConn,
  5446. IN PATALK_ERROR pError
  5447. )
  5448. /*++
  5449. Routine Description:
  5450. The MAC could respond with a REQ&ACK from a different socket than
  5451. the one we sent the REQ to. But the network/node id must be the
  5452. same. We don't check for that though, and only use the destination
  5453. connection id.
  5454. This routine will replace the remote address with the new remote
  5455. address passed in.
  5456. Arguments:
  5457. Return Value:
  5458. --*/
  5459. {
  5460. PADSP_CONNOBJ pAdspRemConn;
  5461. ASSERT(pAdspAddr->adspao_Flags & ADSPAO_CONNECT);
  5462. *pError = ATALK_INVALID_CONNECTION;
  5463. for (pAdspRemConn = pAdspAddr->adspao_pConnectConn;
  5464. pAdspRemConn != NULL; )
  5465. {
  5466. if (pAdspRemConn->adspco_LocalConnId == DestConnId)
  5467. {
  5468. DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
  5469. ("atalkAdspFindInConnectList: connect conn %lx\n",
  5470. pAdspRemConn));
  5471. // Try to reference this.
  5472. AtalkAdspConnReferenceByPtr(pAdspRemConn, pError);
  5473. if (ATALK_SUCCESS(*pError))
  5474. {
  5475. // Change remote address to be the passed in address
  5476. pAdspRemConn->adspco_RemoteAddr = *pRemoteAddr;
  5477. *ppAdspConn = pAdspRemConn;
  5478. }
  5479. break;
  5480. }
  5481. else
  5482. {
  5483. pAdspRemConn = pAdspRemConn->adspco_pNextConnect;
  5484. }
  5485. }
  5486. }
  5487. 
  5488.