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

1743 lines
35 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxcutil.c
  5. Abstract:
  6. This module contains code which implements the CONNECTION object.
  7. Routines are provided to create, destroy, reference, and dereference,
  8. transport connection objects.
  9. Author:
  10. Nikhil Kamkolkar (nikhilk) 11-November-1993
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. Sanjay Anand (SanjayAn) 5-July-1995
  15. Bug fixes - tagged [SA]
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. // Define module number for event logging entries
  20. #define FILENUM SPXCUTIL
  21. //
  22. // Minor utility routines
  23. //
  24. BOOLEAN
  25. spxConnCheckNegSize(
  26. IN PUSHORT pNegSize
  27. )
  28. /*++
  29. Routine Description:
  30. Arguments:
  31. Return Value:
  32. --*/
  33. {
  34. int i;
  35. // We go thru table and see if this is the minimum size or if it
  36. // can go down further. Return true if it is not the minimum size.
  37. DBGPRINT(CONNECT, INFO,
  38. ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
  39. (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
  40. SpxMaxPktSize[0]));
  41. if ((ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE) <= SpxMaxPktSize[0])
  42. return(FALSE);
  43. for (i = SpxMaxPktSizeIndex-1; i > 0; i--)
  44. {
  45. DBGPRINT(CONNECT, INFO,
  46. ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
  47. (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
  48. SpxMaxPktSize[i]));
  49. if (SpxMaxPktSize[i] < (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE))
  50. break;
  51. }
  52. *pNegSize = (USHORT)(SpxMaxPktSize[i] + MIN_IPXSPX2_HDRSIZE);
  53. DBGPRINT(CONNECT, ERR,
  54. ("spxConnCheckNegSize: Trying Size %lx Min size possible %lx\n",
  55. *pNegSize, SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE));
  56. return(TRUE);
  57. }
  58. VOID
  59. spxConnSetNegSize(
  60. IN OUT PNDIS_PACKET pPkt,
  61. IN ULONG Size
  62. )
  63. /*++
  64. Routine Description:
  65. Arguments:
  66. Return Value:
  67. --*/
  68. {
  69. PNDIS_BUFFER pNdisBuffer;
  70. UINT bufCount;
  71. PSPX_SEND_RESD pSendResd;
  72. PIPXSPX_HDR pIpxSpxHdr;
  73. CTEAssert(Size > 0);
  74. NdisQueryPacket(pPkt, NULL, &bufCount, &pNdisBuffer, NULL);
  75. CTEAssert (bufCount == 3);
  76. NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
  77. NdisQueryBuffer(pNdisBuffer, &pIpxSpxHdr, &bufCount);
  78. NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
  79. NdisAdjustBufferLength(pNdisBuffer, Size);
  80. // Change it in send reserved
  81. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  82. pSendResd->sr_Len = (Size + MIN_IPXSPX2_HDRSIZE);
  83. #if SPX_OWN_PACKETS
  84. // Change in ipx header
  85. pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
  86. NDIS_PACKET_SIZE +
  87. sizeof(SPX_SEND_RESD) +
  88. IpxInclHdrOffset);
  89. #endif
  90. PUTSHORT2SHORT((PUSHORT)&pIpxSpxHdr->hdr_PktLen, (Size + MIN_IPXSPX2_HDRSIZE));
  91. // Change in the neg packet field of the header.
  92. PUTSHORT2SHORT(
  93. &pIpxSpxHdr->hdr_NegSize,
  94. (Size + MIN_IPXSPX2_HDRSIZE));
  95. DBGPRINT(CONNECT, DBG,
  96. ("spxConnSetNegSize: Setting size to %lx Hdr %lx\n",
  97. Size, (Size + MIN_IPXSPX2_HDRSIZE)));
  98. return;
  99. }
  100. BOOLEAN
  101. SpxConnDequeueSendPktLock(
  102. IN PSPX_CONN_FILE pSpxConnFile,
  103. IN PNDIS_PACKET pPkt
  104. )
  105. /*++
  106. Routine Description:
  107. Arguments:
  108. Return Value:
  109. --*/
  110. {
  111. PSPX_SEND_RESD pSr, pListHead, pListTail;
  112. PSPX_SEND_RESD pSendResd;
  113. BOOLEAN removed = TRUE;
  114. // If we are sequenced or not decides which list we choose.
  115. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  116. if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
  117. {
  118. pListHead = pSpxConnFile->scf_SendSeqListHead;
  119. pListTail = pSpxConnFile->scf_SendSeqListTail;
  120. }
  121. else
  122. {
  123. pListHead = pSpxConnFile->scf_SendListHead;
  124. pListTail = pSpxConnFile->scf_SendListTail;
  125. }
  126. // Most often, we will be at the head of the list.
  127. if (pListHead == pSendResd)
  128. {
  129. if ((pListHead = pSendResd->sr_Next) == NULL)
  130. {
  131. DBGPRINT(SEND, INFO,
  132. ("SpxConnDequeuePktLock: %lx first in list\n", pSendResd));
  133. pListTail = NULL;
  134. }
  135. }
  136. else
  137. {
  138. DBGPRINT(SEND, INFO,
  139. ("SpxConnDequeuePktLock: %lx !first in list\n", pSendResd));
  140. pSr = pListHead;
  141. while (pSr != NULL)
  142. {
  143. if (pSr->sr_Next == pSendResd)
  144. {
  145. if ((pSr->sr_Next = pSendResd->sr_Next) == NULL)
  146. {
  147. pListTail = pSr;
  148. }
  149. break;
  150. }
  151. pSr = pSr->sr_Next;
  152. }
  153. if (pSr == NULL)
  154. removed = FALSE;
  155. }
  156. if (removed)
  157. {
  158. if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
  159. {
  160. pSpxConnFile->scf_SendSeqListHead = pListHead;
  161. pSpxConnFile->scf_SendSeqListTail = pListTail;
  162. }
  163. else
  164. {
  165. pSpxConnFile->scf_SendListHead = pListHead;
  166. pSpxConnFile->scf_SendListTail = pListTail;
  167. }
  168. }
  169. return(removed);
  170. }
  171. BOOLEAN
  172. SpxConnDequeueRecvPktLock(
  173. IN PSPX_CONN_FILE pSpxConnFile,
  174. IN PNDIS_PACKET pPkt
  175. )
  176. /*++
  177. Routine Description:
  178. Arguments:
  179. Return Value:
  180. --*/
  181. {
  182. PSPX_RECV_RESD pSr, pListHead, pListTail;
  183. PSPX_RECV_RESD pRecvResd;
  184. BOOLEAN removed = TRUE;
  185. pRecvResd = (PSPX_RECV_RESD)(pPkt->ProtocolReserved);
  186. pListHead = pSpxConnFile->scf_RecvListHead;
  187. pListTail = pSpxConnFile->scf_RecvListTail;
  188. // Most often, we will be at the head of the list.
  189. if (pListHead == pRecvResd)
  190. {
  191. DBGPRINT(RECEIVE, INFO,
  192. ("SpxConnDequeuePktLock: %lx first in list\n", pRecvResd));
  193. if ((pListHead = pRecvResd->rr_Next) == NULL)
  194. {
  195. pListTail = NULL;
  196. }
  197. }
  198. else
  199. {
  200. DBGPRINT(RECEIVE, INFO,
  201. ("SpxConnDequeuePktLock: %lx !first in list\n", pRecvResd));
  202. pSr = pListHead;
  203. while (pSr != NULL)
  204. {
  205. if (pSr->rr_Next == pRecvResd)
  206. {
  207. if ((pSr->rr_Next = pRecvResd->rr_Next) == NULL)
  208. {
  209. pListTail = pSr;
  210. }
  211. break;
  212. }
  213. pSr = pSr->rr_Next;
  214. }
  215. if (pSr == NULL)
  216. removed = FALSE;
  217. }
  218. if (removed)
  219. {
  220. pSpxConnFile->scf_RecvListHead = pListHead;
  221. pSpxConnFile->scf_RecvListTail = pListTail;
  222. }
  223. return(removed);
  224. }
  225. BOOLEAN
  226. spxConnGetPktByType(
  227. IN PSPX_CONN_FILE pSpxConnFile,
  228. IN ULONG PktType,
  229. IN BOOLEAN fSeqList,
  230. IN PNDIS_PACKET * ppPkt
  231. )
  232. /*++
  233. Routine Description:
  234. Arguments:
  235. Return Value:
  236. --*/
  237. {
  238. PSPX_SEND_RESD pSr, *ppSr;
  239. // Most often, we will be at the head of the list.
  240. ppSr = (fSeqList ?
  241. &pSpxConnFile->scf_SendSeqListHead :
  242. &pSpxConnFile->scf_SendListHead);
  243. for (; (pSr = *ppSr) != NULL; )
  244. {
  245. if (pSr->sr_Type == PktType)
  246. {
  247. *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  248. pSr, NDIS_PACKET, ProtocolReserved);
  249. DBGPRINT(SEND, INFO,
  250. ("SpxConnFindByType: %lx.%lx.%d\n", pSr,*ppPkt, fSeqList));
  251. break;
  252. }
  253. ppSr = &pSr->sr_Next;
  254. }
  255. return(pSr != NULL);
  256. }
  257. BOOLEAN
  258. spxConnGetPktBySeqNum(
  259. IN PSPX_CONN_FILE pSpxConnFile,
  260. IN USHORT SeqNum,
  261. IN PNDIS_PACKET * ppPkt
  262. )
  263. /*++
  264. Routine Description:
  265. Arguments:
  266. Return Value:
  267. --*/
  268. {
  269. PSPX_SEND_RESD pSr, *ppSr;
  270. // Most often, we will be at the head of the list.
  271. ppSr = &pSpxConnFile->scf_SendSeqListHead;
  272. for (; (pSr = *ppSr) != NULL; )
  273. {
  274. if (pSr->sr_SeqNum == SeqNum)
  275. {
  276. *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  277. pSr, NDIS_PACKET, ProtocolReserved);
  278. DBGPRINT(SEND, DBG,
  279. ("SpxConnFindBySeq: %lx.%lx.%d\n", pSr,*ppPkt, SeqNum));
  280. break;
  281. }
  282. ppSr = &pSr->sr_Next;
  283. }
  284. return(pSr != NULL);
  285. }
  286. USHORT
  287. spxConnGetId(
  288. VOID
  289. )
  290. /*++
  291. Routine Description:
  292. This must be called with the device lock held.
  293. Arguments:
  294. Return Value:
  295. --*/
  296. {
  297. PSPX_CONN_FILE pSpxConnFile;
  298. BOOLEAN wrapped = FALSE;
  299. USHORT startConnId, retConnId;
  300. startConnId = SpxDevice->dev_NextConnId;
  301. // Search the global active list.
  302. do
  303. {
  304. if ((SpxDevice->dev_NextConnId >= startConnId) && wrapped)
  305. {
  306. retConnId = 0;
  307. break;
  308. }
  309. if (SpxDevice->dev_NextConnId == 0xFFFF)
  310. {
  311. wrapped = TRUE;
  312. SpxDevice->dev_NextConnId = 1;
  313. continue;
  314. }
  315. // Later this be a tree.
  316. for (pSpxConnFile = SpxDevice->dev_GlobalActiveConnList[
  317. SpxDevice->dev_NextConnId & NUM_SPXCONN_HASH_MASK];
  318. pSpxConnFile != NULL;
  319. pSpxConnFile = pSpxConnFile->scf_GlobalActiveNext)
  320. {
  321. if (pSpxConnFile->scf_LocalConnId == SpxDevice->dev_NextConnId)
  322. {
  323. break;
  324. }
  325. }
  326. // Increment for next time.
  327. retConnId = SpxDevice->dev_NextConnId++;
  328. // Ensure we are still legal. We could return if connfile is null.
  329. if (SpxDevice->dev_NextConnId == 0xFFFF)
  330. {
  331. wrapped = TRUE;
  332. SpxDevice->dev_NextConnId = 1;
  333. }
  334. if (pSpxConnFile != NULL)
  335. {
  336. continue;
  337. }
  338. break;
  339. } while (TRUE);
  340. return(retConnId);
  341. }
  342. NTSTATUS
  343. spxConnRemoveFromList(
  344. IN PSPX_CONN_FILE * ppConnListHead,
  345. IN PSPX_CONN_FILE pConnRemove
  346. )
  347. /*++
  348. Routine Description:
  349. This routine must be called with the address lock (and the lock of the remove
  350. connection will usually also be, but is not needed) held.
  351. Arguments:
  352. Return Value:
  353. --*/
  354. {
  355. PSPX_CONN_FILE pRemConn, *ppRemConn;
  356. NTSTATUS status = STATUS_SUCCESS;
  357. // Dequeue the connection file from the address list. It must be
  358. // in the inactive list.
  359. for (ppRemConn = ppConnListHead;
  360. (pRemConn = *ppRemConn) != NULL;)
  361. {
  362. if (pRemConn == pConnRemove)
  363. {
  364. *ppRemConn = pRemConn->scf_Next;
  365. break;
  366. }
  367. ppRemConn = &pRemConn->scf_Next;
  368. }
  369. if (pRemConn == NULL)
  370. {
  371. DBGBRK(FATAL);
  372. CTEAssert(0);
  373. status = STATUS_INVALID_CONNECTION;
  374. }
  375. return(status);
  376. }
  377. NTSTATUS
  378. spxConnRemoveFromAssocList(
  379. IN PSPX_CONN_FILE * ppConnListHead,
  380. IN PSPX_CONN_FILE pConnRemove
  381. )
  382. /*++
  383. Routine Description:
  384. This routine must be called with the address lock (and the lock of the remove
  385. connection will usually also be, but is not needed) held.
  386. Arguments:
  387. Return Value:
  388. --*/
  389. {
  390. PSPX_CONN_FILE pRemConn, *ppRemConn;
  391. NTSTATUS status = STATUS_SUCCESS;
  392. // Dequeue the connection file from the address list. It must be
  393. // in the inactive list.
  394. for (ppRemConn = ppConnListHead;
  395. (pRemConn = *ppRemConn) != NULL;)
  396. {
  397. if (pRemConn == pConnRemove)
  398. {
  399. *ppRemConn = pRemConn->scf_AssocNext;
  400. break;
  401. }
  402. ppRemConn = &pRemConn->scf_AssocNext;
  403. }
  404. if (pRemConn == NULL)
  405. {
  406. CTEAssert(0);
  407. status = STATUS_INVALID_CONNECTION;
  408. }
  409. return(status);
  410. }
  411. VOID
  412. spxConnInsertIntoGlobalActiveList(
  413. IN PSPX_CONN_FILE pSpxConnFile
  414. )
  415. /*++
  416. Routine Description:
  417. This routine must be called with the device lock held.
  418. Arguments:
  419. Return Value:
  420. --*/
  421. {
  422. int index = (int)(pSpxConnFile->scf_LocalConnId &
  423. NUM_SPXCONN_HASH_MASK);
  424. // For now, its just a linear list.
  425. pSpxConnFile->scf_GlobalActiveNext =
  426. SpxDevice->dev_GlobalActiveConnList[index];
  427. SpxDevice->dev_GlobalActiveConnList[index] =
  428. pSpxConnFile;
  429. return;
  430. }
  431. NTSTATUS
  432. spxConnRemoveFromGlobalActiveList(
  433. IN PSPX_CONN_FILE pSpxConnFile
  434. )
  435. /*++
  436. Routine Description:
  437. This routine must be called with the device lock held.
  438. Arguments:
  439. Return Value:
  440. --*/
  441. {
  442. PSPX_CONN_FILE pC, *ppC;
  443. int index = (int)(pSpxConnFile->scf_LocalConnId &
  444. NUM_SPXCONN_HASH_MASK);
  445. NTSTATUS status = STATUS_SUCCESS;
  446. // For now, its just a linear list.
  447. for (ppC = &SpxDevice->dev_GlobalActiveConnList[index];
  448. (pC = *ppC) != NULL;)
  449. {
  450. if (pC == pSpxConnFile)
  451. {
  452. DBGPRINT(SEND, INFO,
  453. ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
  454. // Remove from list
  455. *ppC = pC->scf_GlobalActiveNext;
  456. break;
  457. }
  458. ppC = &pC->scf_GlobalActiveNext;
  459. }
  460. if (pC == NULL)
  461. status = STATUS_INVALID_CONNECTION;
  462. return(status);
  463. }
  464. VOID
  465. spxConnInsertIntoGlobalList(
  466. IN PSPX_CONN_FILE pSpxConnFile
  467. )
  468. /*++
  469. Routine Description:
  470. Arguments:
  471. Return Value:
  472. --*/
  473. {
  474. CTELockHandle lockHandle;
  475. // Get the global q lock
  476. CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
  477. pSpxConnFile->scf_GlobalNext = SpxGlobalConnList;
  478. SpxGlobalConnList = pSpxConnFile;
  479. CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
  480. return;
  481. }
  482. NTSTATUS
  483. spxConnRemoveFromGlobalList(
  484. IN PSPX_CONN_FILE pSpxConnFile
  485. )
  486. /*++
  487. Routine Description:
  488. Arguments:
  489. Return Value:
  490. --*/
  491. {
  492. CTELockHandle lockHandle;
  493. PSPX_CONN_FILE pC, *ppC;
  494. NTSTATUS status = STATUS_SUCCESS;
  495. // Get the global q lock
  496. CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
  497. for (ppC = &SpxGlobalConnList;
  498. (pC = *ppC) != NULL;)
  499. {
  500. if (pC == pSpxConnFile)
  501. {
  502. DBGPRINT(SEND, DBG,
  503. ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
  504. // Remove from list
  505. *ppC = pC->scf_GlobalNext;
  506. break;
  507. }
  508. ppC = &pC->scf_GlobalNext;
  509. }
  510. CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
  511. if (pC == NULL)
  512. status = STATUS_INVALID_CONNECTION;
  513. return(status);
  514. }
  515. #if 0
  516. VOID
  517. spxConnPushIntoPktList(
  518. IN PSPX_CONN_FILE pSpxConnFile
  519. )
  520. /*++
  521. Routine Description:
  522. !!!MACROIZE!!!
  523. Arguments:
  524. Return Value:
  525. --*/
  526. {
  527. CTELockHandle lockHandle;
  528. // Get the global q lock
  529. CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
  530. pSpxConnFile->scf_PktNext = SpxPktConnList;
  531. SpxPktConnList = pSpxConnFile;
  532. CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
  533. return;
  534. }
  535. VOID
  536. spxConnPopFromPktList(
  537. IN PSPX_CONN_FILE * ppSpxConnFile
  538. )
  539. /*++
  540. Routine Description:
  541. !!!MACROIZE!!!
  542. Arguments:
  543. Return Value:
  544. --*/
  545. {
  546. CTELockHandle lockHandle;
  547. // Get the global q lock
  548. CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
  549. if ((*ppSpxConnFile = SpxPktConnList) != NULL)
  550. {
  551. SpxPktConnList = SpxPktConnList->scf_PktNext;
  552. DBGPRINT(SEND, DBG,
  553. ("SpxConnRemoveFromPkt: %lx\n", *ppSpxConnFile));
  554. }
  555. CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
  556. return;
  557. }
  558. VOID
  559. spxConnPushIntoRecvList(
  560. IN PSPX_CONN_FILE pSpxConnFile
  561. )
  562. /*++
  563. Routine Description:
  564. !!!MACROIZE!!!
  565. Arguments:
  566. Return Value:
  567. --*/
  568. {
  569. CTELockHandle lockHandle;
  570. // Get the global q lock
  571. CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
  572. pSpxConnFile->scf_ProcessRecvNext = SpxRecvConnList;
  573. SpxRecvConnList = pSpxConnFile;
  574. CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
  575. return;
  576. }
  577. VOID
  578. spxConnPopFromRecvList(
  579. IN PSPX_CONN_FILE * ppSpxConnFile
  580. )
  581. /*++
  582. Routine Description:
  583. !!!MACROIZE!!!
  584. Arguments:
  585. Return Value:
  586. --*/
  587. {
  588. CTELockHandle lockHandle;
  589. // Get the global q lock
  590. CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
  591. if ((*ppSpxConnFile = SpxRecvConnList) != NULL)
  592. {
  593. SpxRecvConnList = SpxRecvConnList->scf_ProcessRecvNext;
  594. DBGPRINT(SEND, INFO,
  595. ("SpxConnRemoveFromRecv: %lx\n", *ppSpxConnFile));
  596. }
  597. CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
  598. return;
  599. }
  600. #endif
  601. //
  602. // Reference/Dereference routines
  603. //
  604. #if DBG
  605. VOID
  606. SpxConnFileRef(
  607. IN PSPX_CONN_FILE pSpxConnFile
  608. )
  609. /*++
  610. Routine Description:
  611. This routine increments the reference count on an address file.
  612. Arguments:
  613. pSpxConnFile - Pointer to a transport address file object.
  614. Return Value:
  615. none.
  616. --*/
  617. {
  618. CTEAssert ((LONG)pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
  619. (VOID)SPX_ADD_ULONG (
  620. &pSpxConnFile->scf_RefCount,
  621. 1,
  622. &pSpxConnFile->scf_Lock);
  623. } // SpxRefConnectionFile
  624. VOID
  625. SpxConnFileLockRef(
  626. IN PSPX_CONN_FILE pSpxConnFile
  627. )
  628. /*++
  629. Routine Description:
  630. This routine increments the reference count on an address file.
  631. IT IS CALLED WITH THE CONNECTION LOCK HELD.
  632. Arguments:
  633. pSpxConnFile - Pointer to a transport address file object.
  634. Return Value:
  635. none.
  636. --*/
  637. {
  638. CTEAssert ((LONG)pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
  639. (VOID)SPX_ADD_ULONG (
  640. &pSpxConnFile->scf_RefCount,
  641. 1,
  642. &pSpxConnFile->scf_Lock);
  643. } // SpxRefConnectionFileLock
  644. #endif
  645. VOID
  646. SpxConnFileRefByIdLock (
  647. IN USHORT ConnId,
  648. OUT PSPX_CONN_FILE * ppSpxConnFile,
  649. OUT PNTSTATUS pStatus
  650. )
  651. /*++
  652. Routine Description:
  653. !!!MUST BE CALLED WITH THE DEVICE LOCK HELD!!!
  654. All active connections should be on the device active list. Later,
  655. this data structure will be a tree, caching the last accessed
  656. connection.
  657. Arguments:
  658. Return Value:
  659. STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
  660. --*/
  661. {
  662. PSPX_CONN_FILE pSpxChkConn;
  663. *pStatus = STATUS_SUCCESS;
  664. for (pSpxChkConn =
  665. SpxDevice->dev_GlobalActiveConnList[ConnId & NUM_SPXCONN_HASH_MASK];
  666. pSpxChkConn != NULL;
  667. pSpxChkConn = pSpxChkConn->scf_GlobalActiveNext)
  668. {
  669. if (pSpxChkConn->scf_LocalConnId == ConnId)
  670. {
  671. SpxConnFileReference(pSpxChkConn, CFREF_BYID);
  672. *ppSpxConnFile = pSpxChkConn;
  673. break;
  674. }
  675. }
  676. if (pSpxChkConn == NULL)
  677. {
  678. *pStatus = STATUS_INVALID_CONNECTION;
  679. }
  680. return;
  681. }
  682. VOID
  683. SpxConnFileRefByCtxLock(
  684. IN PSPX_ADDR_FILE pSpxAddrFile,
  685. IN CONNECTION_CONTEXT Ctx,
  686. OUT PSPX_CONN_FILE * ppSpxConnFile,
  687. OUT PNTSTATUS pStatus
  688. )
  689. /*++
  690. Routine Description:
  691. !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
  692. Returns a referenced connection file with the associated context and
  693. address file desired.
  694. Arguments:
  695. Return Value:
  696. --*/
  697. {
  698. PSPX_CONN_FILE pSpxChkConn = NULL;
  699. BOOLEAN Found = FALSE;
  700. *pStatus = STATUS_SUCCESS;
  701. for (pSpxChkConn = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
  702. pSpxChkConn != NULL;
  703. pSpxChkConn = pSpxChkConn->scf_Next)
  704. {
  705. if ((pSpxChkConn->scf_ConnCtx == Ctx) &&
  706. (pSpxChkConn->scf_AddrFile == pSpxAddrFile))
  707. {
  708. SpxConnFileReference(pSpxChkConn, CFREF_BYCTX);
  709. *ppSpxConnFile = pSpxChkConn;
  710. Found = TRUE;
  711. break;
  712. }
  713. }
  714. if (!Found)
  715. {
  716. *pStatus = STATUS_INVALID_CONNECTION;
  717. }
  718. return;
  719. }
  720. NTSTATUS
  721. SpxConnFileVerify (
  722. IN PSPX_CONN_FILE pConnFile
  723. )
  724. /*++
  725. Routine Description:
  726. This routine is called to verify that the pointer given us in a file
  727. object is in fact a valid address file object. We also verify that the
  728. address object pointed to by it is a valid address object, and reference
  729. it to keep it from disappearing while we use it.
  730. Arguments:
  731. Return Value:
  732. STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
  733. --*/
  734. {
  735. CTELockHandle LockHandle;
  736. NTSTATUS status = STATUS_SUCCESS;
  737. try
  738. {
  739. if ((pConnFile->scf_Size == sizeof (SPX_CONN_FILE)) &&
  740. (pConnFile->scf_Type == SPX_CONNFILE_SIGNATURE))
  741. {
  742. CTEGetLock (&pConnFile->scf_Lock, &LockHandle);
  743. if (!SPX_CONN_FLAG(pConnFile, SPX_CONNFILE_CLOSING))
  744. {
  745. SpxConnFileLockReference(pConnFile, CFREF_VERIFY);
  746. }
  747. else
  748. {
  749. DBGPRINT(TDI, ERR,
  750. ("StVerifyConnFile: A %lx closing\n", pConnFile));
  751. status = STATUS_INVALID_CONNECTION;
  752. }
  753. CTEFreeLock (&pConnFile->scf_Lock, LockHandle);
  754. }
  755. else
  756. {
  757. DBGPRINT(TDI, ERR,
  758. ("StVerifyAddressFile: AF %lx bad signature\n", pConnFile));
  759. status = STATUS_INVALID_CONNECTION;
  760. }
  761. } except(EXCEPTION_EXECUTE_HANDLER) {
  762. DBGPRINT(TDI, ERR,
  763. ("SpxVerifyConnFile: AF %lx exception\n", pConnFile));
  764. return GetExceptionCode();
  765. }
  766. return status;
  767. } // SpxVerifyConnFile
  768. VOID
  769. SpxConnFileDeref(
  770. IN PSPX_CONN_FILE pSpxConnFile
  771. )
  772. /*++
  773. Routine Description:
  774. This routine dereferences an address file by decrementing the
  775. reference count contained in the structure. If, after being
  776. decremented, the reference count is zero, then this routine calls
  777. SpxDestroyConnectionFile to remove it from the system.
  778. Arguments:
  779. pSpxConnFile - Pointer to a transport address file object.
  780. Return Value:
  781. none.
  782. --*/
  783. {
  784. ULONG oldvalue;
  785. BOOLEAN fDiscNotIndicated = FALSE;
  786. BOOLEAN fIDiscFlag = FALSE;
  787. BOOLEAN fSpx2;
  788. CTEAssert(pSpxConnFile->scf_RefCount > 0);
  789. oldvalue = SPX_ADD_ULONG (
  790. &pSpxConnFile->scf_RefCount,
  791. (ULONG)-1,
  792. &pSpxConnFile->scf_Lock);
  793. CTEAssert (oldvalue > 0);
  794. if (oldvalue == 1)
  795. {
  796. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  797. LIST_ENTRY discReqList, *p;
  798. PREQUEST pDiscReq;
  799. PSPX_ADDR_FILE pSpxAddrFile = NULL;
  800. PREQUEST pCloseReq = NULL,
  801. pCleanupReq = NULL,
  802. pConnectReq = NULL;
  803. BOOLEAN fDisassoc = FALSE;
  804. InitializeListHead(&discReqList);
  805. // We may not be associated at this point. Note: When we are active we
  806. // always have a reference. So its not like we execute this code very often.
  807. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  808. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
  809. {
  810. pSpxAddrFile = pSpxConnFile->scf_AddrFile;
  811. }
  812. else
  813. {
  814. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
  815. {
  816. DBGPRINT(TDI, DBG,
  817. ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
  818. pSpxConnFile,
  819. pSpxConnFile->scf_CleanupReq));
  820. // Save this for later completion.
  821. pCleanupReq = pSpxConnFile->scf_CleanupReq;
  822. pSpxConnFile->scf_CleanupReq = NULL;
  823. }
  824. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
  825. {
  826. DBGPRINT(TDI, DBG,
  827. ("SpxDerefConnectionFile: Conn closing %lx\n",
  828. pSpxConnFile));
  829. // Save this for later completion.
  830. pCloseReq = pSpxConnFile->scf_CloseReq;
  831. //
  832. // Null this out so on a re-entrant case, we dont try to complete this again.
  833. //
  834. pSpxConnFile->scf_CloseReq = NULL;
  835. CTEAssert(pCloseReq != NULL);
  836. }
  837. }
  838. CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
  839. if (pSpxAddrFile)
  840. {
  841. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  842. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
  843. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  844. //if (pSpxConnFile->scf_RefCount == 0)
  845. //
  846. // ** The lock passed here is a dummy - it is pre-compiled out.
  847. //
  848. if (SPX_ADD_ULONG(&pSpxConnFile->scf_RefCount, 0, &pSpxConnFile->scf_Lock) == 0)
  849. {
  850. DBGPRINT(TDI, INFO,
  851. ("SpxDerefConnectionFile: Conn is 0 %lx.%lx\n",
  852. pSpxConnFile, pSpxConnFile->scf_Flags));
  853. // All pending requests on this connection are done. See if we
  854. // need to complete the disconnect phase etc.
  855. switch (SPX_MAIN_STATE(pSpxConnFile))
  856. {
  857. case SPX_CONNFILE_DISCONN:
  858. // Disconnect is done. Move connection out of all the lists
  859. // it is on, reset states etc.
  860. DBGPRINT(TDI, INFO,
  861. ("SpxDerefConnectionFile: Conn being inactivated %lx\n",
  862. pSpxConnFile));
  863. // Time to complete disc requests if present.
  864. // There could be multiple of them.
  865. p = pSpxConnFile->scf_DiscLinkage.Flink;
  866. while (p != &pSpxConnFile->scf_DiscLinkage)
  867. {
  868. pDiscReq = LIST_ENTRY_TO_REQUEST(p);
  869. p = p->Flink;
  870. DBGPRINT(TDI, DBG,
  871. ("SpxDerefConnectionFile: Disc on %lx.%lx\n",
  872. pSpxConnFile, pDiscReq));
  873. RemoveEntryList(REQUEST_LINKAGE(pDiscReq));
  874. if (REQUEST_STATUS(pDiscReq) == STATUS_PENDING)
  875. {
  876. REQUEST_STATUS(pDiscReq) = STATUS_SUCCESS;
  877. }
  878. InsertTailList(
  879. &discReqList,
  880. REQUEST_LINKAGE(pDiscReq));
  881. }
  882. //
  883. // Note the state here, and check after the conn has been inactivated.
  884. //
  885. //
  886. // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
  887. //
  888. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
  889. !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)) {
  890. fDiscNotIndicated = TRUE;
  891. }
  892. if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC)) {
  893. fIDiscFlag = TRUE;
  894. }
  895. fSpx2 = (SPX2_CONN(pSpxConnFile)) ? TRUE : FALSE;
  896. //
  897. // [SA] Bug #14655
  898. // Do not try to inactivate an already inactivated connection
  899. //
  900. if (!(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
  901. spxConnInactivate(pSpxConnFile);
  902. } else {
  903. //
  904. // This is an SPXI connection which has got the local disconnect.
  905. // Reset the flags now.
  906. //
  907. CTEAssert(!fDiscNotIndicated);
  908. SPX_MAIN_SETSTATE(pSpxConnFile, 0);
  909. SPX_DISC_SETSTATE(pSpxConnFile, 0);
  910. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
  911. }
  912. //
  913. // [SA] If we were waiting for sends to be aborted and did not indicate this
  914. // disconnect to AFD; and AFD did not call a disconnect on this connection,
  915. // then call the disonnect handler now.
  916. //
  917. if (fDiscNotIndicated) {
  918. PVOID pDiscHandlerCtx;
  919. PTDI_IND_DISCONNECT pDiscHandler = NULL;
  920. ULONG discCode = 0;
  921. pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
  922. pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
  923. // Indicate disconnect to afd.
  924. if (pDiscHandler != NULL) {
  925. //
  926. // If this was an SPXI connection, the disconnect state is still
  927. // DISCONN, so if this routine is re-entered, we need to prevent
  928. // a re-indicate to AFD.
  929. // Also, we need to wait for a local disconnect from AFD since
  930. // we indicated a TDI_DISCONNECT_RELEASE. We bump up the ref count
  931. // in this case.
  932. //
  933. if (!fSpx2) {
  934. CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  935. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) );
  936. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
  937. if (fIDiscFlag) {
  938. SpxConnFileLockReference(pSpxConnFile, CFREF_DISCWAITSPX);
  939. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
  940. }
  941. }
  942. CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
  943. CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
  944. CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
  945. DBGPRINT(CONNECT, INFO,
  946. ("spxDerefConnectionFile: Indicating to afd On %lx when %lx\n",
  947. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  948. // First complete all requests waiting for receive completion on
  949. // this conn before indicating disconnect.
  950. spxConnCompletePended(pSpxConnFile);
  951. if (fIDiscFlag) {
  952. //
  953. // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
  954. // it has buffered before the remote disconnect took place.
  955. //
  956. discCode = TDI_DISCONNECT_RELEASE;
  957. } else {
  958. //
  959. // [SA] bug #15249
  960. // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
  961. //
  962. discCode = TDI_DISCONNECT_ABORT;
  963. }
  964. (*pDiscHandler)(
  965. pDiscHandlerCtx,
  966. pSpxConnFile->scf_ConnCtx,
  967. 0, // Disc data
  968. NULL,
  969. 0, // Disc info
  970. NULL,
  971. discCode);
  972. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  973. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
  974. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  975. }
  976. }
  977. --SpxDevice->dev_Stat.OpenConnections;
  978. break;
  979. case SPX_CONNFILE_CONNECTING:
  980. case SPX_CONNFILE_LISTENING:
  981. // Get connect/accept request if present.
  982. pConnectReq = pSpxConnFile->scf_ConnectReq;
  983. pSpxConnFile->scf_ConnectReq = NULL;
  984. spxConnInactivate(pSpxConnFile);
  985. break;
  986. case SPX_CONNFILE_ACTIVE:
  987. KeBugCheck(0);
  988. default:
  989. CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == 0);
  990. break;
  991. }
  992. // If stopping, disassociate from the address file. Complete
  993. // cleanup request.
  994. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
  995. {
  996. DBGPRINT(TDI, DBG,
  997. ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
  998. pSpxConnFile,
  999. pSpxConnFile->scf_CleanupReq));
  1000. // Save this for later completion.
  1001. pCleanupReq = pSpxConnFile->scf_CleanupReq;
  1002. pSpxConnFile->scf_CleanupReq = NULL;
  1003. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
  1004. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
  1005. {
  1006. DBGPRINT(TDI, INFO,
  1007. ("SpxDerefConnectionFile: Conn stopping %lx\n",
  1008. pSpxConnFile));
  1009. pSpxAddrFile = pSpxConnFile->scf_AddrFile;
  1010. SPX_CONN_RESETFLAG(pSpxConnFile,SPX_CONNFILE_ASSOC);
  1011. // Dequeue the connection from the address file
  1012. spxConnRemoveFromAssocList(
  1013. &pSpxAddrFile->saf_AssocConnList,
  1014. pSpxConnFile);
  1015. // Dequeue the connection file from the address list. It must
  1016. // be in the inactive list.
  1017. spxConnRemoveFromList(
  1018. &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
  1019. pSpxConnFile);
  1020. DBGPRINT(CREATE, INFO,
  1021. ("SpxConnDerefDisAssociate: %lx from addr file %lx\n",
  1022. pSpxConnFile, pSpxAddrFile));
  1023. fDisassoc = TRUE;
  1024. }
  1025. }
  1026. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
  1027. {
  1028. DBGPRINT(TDI, DBG,
  1029. ("SpxDerefConnectionFile: Conn closing %lx\n",
  1030. pSpxConnFile));
  1031. // Save this for later completion.
  1032. pCloseReq = pSpxConnFile->scf_CloseReq;
  1033. //
  1034. // Null this out so on a re-entrant case, we dont try to complete this again.
  1035. //
  1036. pSpxConnFile->scf_CloseReq = NULL;
  1037. CTEAssert(pCloseReq != NULL);
  1038. }
  1039. CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
  1040. CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
  1041. CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
  1042. }
  1043. CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
  1044. CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
  1045. CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
  1046. }
  1047. if (fDisassoc)
  1048. {
  1049. // Remove reference on address for this association.
  1050. SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
  1051. }
  1052. if (pConnectReq != (PREQUEST)NULL)
  1053. {
  1054. DBGPRINT(TDI, DBG,
  1055. ("SpxDerefConnectionFile: Connect on %lx req %lx\n",
  1056. pSpxConnFile, pConnectReq));
  1057. // Status will already be set in here. We should be here only if
  1058. // connect is being aborted.
  1059. SpxCompleteRequest(pConnectReq);
  1060. }
  1061. while (!IsListEmpty(&discReqList))
  1062. {
  1063. p = RemoveHeadList(&discReqList);
  1064. pDiscReq = LIST_ENTRY_TO_REQUEST(p);
  1065. DBGPRINT(CONNECT, DBG,
  1066. ("SpxConnFileDeref: DISC REQ %lx.%lx Completing\n",
  1067. pSpxConnFile, pDiscReq));
  1068. SpxCompleteRequest(pDiscReq);
  1069. }
  1070. if (pCleanupReq != (PREQUEST)NULL)
  1071. {
  1072. DBGPRINT(TDI, DBG,
  1073. ("SpxDerefConnectionFile: Cleanup complete %lx req %lx\n",
  1074. pSpxConnFile, pCleanupReq));
  1075. REQUEST_INFORMATION(pCleanupReq) = 0;
  1076. REQUEST_STATUS(pCleanupReq) = STATUS_SUCCESS;
  1077. SpxCompleteRequest (pCleanupReq);
  1078. }
  1079. if (pCloseReq != (PREQUEST)NULL)
  1080. {
  1081. DBGPRINT(TDI, DBG,
  1082. ("SpxDerefConnectionFile: Freed %lx close req %lx\n",
  1083. pSpxConnFile, pCloseReq));
  1084. CTEAssert(pSpxConnFile->scf_RefCount == 0);
  1085. // Remove from the global list
  1086. if (!NT_SUCCESS(spxConnRemoveFromGlobalList(pSpxConnFile)))
  1087. {
  1088. KeBugCheck(0);
  1089. }
  1090. // Free it up.
  1091. SpxFreeMemory (pSpxConnFile);
  1092. REQUEST_INFORMATION(pCloseReq) = 0;
  1093. REQUEST_STATUS(pCloseReq) = STATUS_SUCCESS;
  1094. SpxCompleteRequest (pCloseReq);
  1095. }
  1096. }
  1097. return;
  1098. } // SpxDerefConnectionFile
  1099. VOID
  1100. spxConnReInit(
  1101. IN PSPX_CONN_FILE pSpxConnFile
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Arguments:
  1106. Return Value:
  1107. --*/
  1108. {
  1109. // Reinit all variables.
  1110. pSpxConnFile->scf_Flags2 = 0;
  1111. pSpxConnFile->scf_GlobalActiveNext = NULL;
  1112. pSpxConnFile->scf_PktNext = NULL;
  1113. pSpxConnFile->scf_CRetryCount = 0;
  1114. pSpxConnFile->scf_WRetryCount = 0;
  1115. pSpxConnFile->scf_RRetryCount = 0;
  1116. pSpxConnFile->scf_RRetrySeqNum = 0;
  1117. pSpxConnFile->scf_CTimerId =
  1118. pSpxConnFile->scf_RTimerId =
  1119. pSpxConnFile->scf_WTimerId =
  1120. pSpxConnFile->scf_TTimerId =
  1121. pSpxConnFile->scf_ATimerId = 0;
  1122. pSpxConnFile->scf_LocalConnId =
  1123. pSpxConnFile->scf_SendSeqNum =
  1124. pSpxConnFile->scf_SentAllocNum =
  1125. pSpxConnFile->scf_RecvSeqNum =
  1126. pSpxConnFile->scf_RetrySeqNum =
  1127. pSpxConnFile->scf_RecdAckNum =
  1128. pSpxConnFile->scf_RemConnId =
  1129. pSpxConnFile->scf_RecdAllocNum = 0;
  1130. #if DBG
  1131. // Initialize so we dont hit breakpoint on seq 0
  1132. pSpxConnFile->scf_PktSeqNum = 0xFFFF;
  1133. #endif
  1134. pSpxConnFile->scf_DataType = 0;
  1135. CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
  1136. CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
  1137. CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
  1138. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  1139. CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
  1140. CTEAssert(pSpxConnFile->scf_SendListHead == NULL);
  1141. CTEAssert(pSpxConnFile->scf_SendListTail == NULL);
  1142. CTEAssert(pSpxConnFile->scf_SendSeqListHead == NULL);
  1143. CTEAssert(pSpxConnFile->scf_SendSeqListTail == NULL);
  1144. pSpxConnFile->scf_CurRecvReq = NULL;
  1145. pSpxConnFile->scf_CurRecvOffset = 0;
  1146. pSpxConnFile->scf_CurRecvSize = 0;
  1147. pSpxConnFile->scf_ReqPkt = NULL;
  1148. return;
  1149. }
  1150. VOID
  1151. spxConnInactivate(
  1152. IN PSPX_CONN_FILE pSpxConnFile
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. !!! Called with dev/addr/connection lock held !!!
  1157. Arguments:
  1158. This gets us back to associate SAVING the state of the STOPPING and
  1159. CLOSING flags so that dereference can go ahead and finish those.
  1160. Return Value:
  1161. --*/
  1162. {
  1163. BOOLEAN fStopping, fClosing, fAborting;
  1164. fStopping = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
  1165. fClosing = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
  1166. //
  1167. // [SA] Bug #14655
  1168. // Save the disconnect states so that a proper error can be given in the case of
  1169. // a send after a remote disconnection.
  1170. //
  1171. //
  1172. // Bug #17729
  1173. // Dont retain these flags if a local disconnect has already occured.
  1174. //
  1175. fAborting = (!SPX2_CONN(pSpxConnFile) &&
  1176. !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
  1177. (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  1178. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT));
  1179. #if DBG
  1180. pSpxConnFile->scf_GhostFlags = pSpxConnFile->scf_Flags;
  1181. pSpxConnFile->scf_GhostFlags2 = pSpxConnFile->scf_Flags2;
  1182. pSpxConnFile->scf_GhostRefCount = pSpxConnFile->scf_RefCount;
  1183. #endif
  1184. // Clear all flags, go back to the assoc state. Restore stop/close
  1185. pSpxConnFile->scf_Flags = SPX_CONNFILE_ASSOC;
  1186. SPX_CONN_SETFLAG(pSpxConnFile,
  1187. ((fStopping ? SPX_CONNFILE_STOPPING : 0) |
  1188. (fClosing ? SPX_CONNFILE_CLOSING : 0)));
  1189. //
  1190. // [SA] bug #14655
  1191. // In order to avoid a re-entry, mark connection as SPX_DISC_INACTIVATED
  1192. //
  1193. if (fAborting)
  1194. {
  1195. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
  1196. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_INACTIVATED);
  1197. }
  1198. // Remove connection from global list on device
  1199. if (!NT_SUCCESS(spxConnRemoveFromGlobalActiveList(
  1200. pSpxConnFile)))
  1201. {
  1202. KeBugCheck(0);
  1203. }
  1204. // Remove connection from active list on address
  1205. if (!NT_SUCCESS(spxConnRemoveFromList(
  1206. &pSpxConnFile->scf_AddrFile->saf_Addr->sa_ActiveConnList,
  1207. pSpxConnFile)))
  1208. {
  1209. KeBugCheck(0);
  1210. }
  1211. // Put connection in inactive list on address
  1212. SPX_INSERT_ADDR_INACTIVE(
  1213. pSpxConnFile->scf_AddrFile->saf_Addr,
  1214. pSpxConnFile);
  1215. spxConnReInit(pSpxConnFile);
  1216. return;
  1217. }