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.

3844 lines
96 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxconn.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. extern POBJECT_TYPE *IoFileObjectType;
  19. #pragma hdrstop
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, SpxConnOpen)
  22. #endif
  23. // Define module number for event logging entries
  24. #define FILENUM SPXCONN
  25. VOID
  26. SpxFindRouteComplete (
  27. IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
  28. IN BOOLEAN FoundRoute);
  29. NTSTATUS
  30. SpxConnOpen(
  31. IN PDEVICE pDevice,
  32. IN CONNECTION_CONTEXT ConnCtx,
  33. IN PREQUEST pRequest
  34. )
  35. /*++
  36. Routine Description:
  37. This routine is used to create a connection object and associate the
  38. passed ConnectionContext with it.
  39. Arguments:
  40. pConnCtx - The TDI ConnectionContext to be associated with object
  41. Return Value:
  42. STATUS_SUCCESS if connection was successfully opened
  43. Error otherwise.
  44. --*/
  45. {
  46. NTSTATUS status = STATUS_SUCCESS;
  47. PSPX_CONN_FILE pSpxConnFile;
  48. #ifdef ISN_NT
  49. PIRP Irp = (PIRP)pRequest;
  50. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  51. #endif
  52. // Allocate memory for a connection object
  53. if ((pSpxConnFile = SpxAllocateZeroedMemory(sizeof(SPX_CONN_FILE))) == NULL)
  54. {
  55. return(STATUS_INSUFFICIENT_RESOURCES);
  56. }
  57. // Initialize values
  58. pSpxConnFile->scf_Flags = 0;
  59. pSpxConnFile->scf_Type = SPX_CONNFILE_SIGNATURE;
  60. pSpxConnFile->scf_Size = sizeof (SPX_CONN_FILE);
  61. CTEInitLock (&pSpxConnFile->scf_Lock);
  62. pSpxConnFile->scf_ConnCtx = ConnCtx;
  63. pSpxConnFile->scf_Device = pDevice;
  64. // Initialize list for requests.
  65. InitializeListHead(&pSpxConnFile->scf_ReqLinkage);
  66. InitializeListHead(&pSpxConnFile->scf_RecvLinkage);
  67. InitializeListHead(&pSpxConnFile->scf_RecvDoneLinkage);
  68. InitializeListHead(&pSpxConnFile->scf_ReqDoneLinkage);
  69. InitializeListHead(&pSpxConnFile->scf_DiscLinkage);
  70. #ifdef ISN_NT
  71. // easy backlink to file object.
  72. pSpxConnFile->scf_FileObject = IrpSp->FileObject;
  73. #endif
  74. // For connections we go from 0->0 with flags indicating if a close
  75. // happened.
  76. pSpxConnFile->scf_RefCount = 0;
  77. // Insert into a global connection list.
  78. spxConnInsertIntoGlobalList(pSpxConnFile);
  79. #if DBG
  80. // Initialize this to 0xFFFF so we dont hit assert on first packet.
  81. pSpxConnFile->scf_PktSeqNum = 0xFFFF;
  82. #endif
  83. // Set values in the request.
  84. REQUEST_OPEN_CONTEXT(pRequest) = (PVOID)pSpxConnFile;
  85. REQUEST_OPEN_TYPE(pRequest) = (PVOID)TDI_CONNECTION_FILE;
  86. DBGPRINT(CREATE, INFO,
  87. ("SpxConnOpen: Opened %lx\n", pSpxConnFile));
  88. ASSERT(status == STATUS_SUCCESS);
  89. return(status);
  90. }
  91. NTSTATUS
  92. SpxConnCleanup(
  93. IN PDEVICE Device,
  94. IN PREQUEST Request
  95. )
  96. /*++
  97. Routine Description:
  98. Arguments:
  99. Request - the close request.
  100. Return Value:
  101. STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
  102. request does not point to a real connection
  103. --*/
  104. {
  105. NTSTATUS status;
  106. CTELockHandle lockHandle;
  107. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
  108. // Verify connection file
  109. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  110. {
  111. DBGBRK(FATAL);
  112. return (status);
  113. }
  114. DBGPRINT(CREATE, INFO,
  115. ("SpxConnFileCleanup: %lx.%lx when %lx\n",
  116. pSpxConnFile, Request, pSpxConnFile->scf_RefCount));
  117. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  118. pSpxConnFile->scf_CleanupReq = Request;
  119. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  120. // We have a reference, so it wont go to zero until stop returns. Therefore
  121. // deref can expect flag to be set.
  122. SpxConnStop(pSpxConnFile);
  123. SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
  124. //
  125. // If this is a connection which is waiting for a local disconnect,
  126. // deref it since we dont expect a disconnect after a cleanup.
  127. //
  128. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  129. if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
  130. CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  131. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
  132. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
  133. CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
  134. SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
  135. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  136. KdPrint(("Deref for DISCWAIT on connfile: %lx\n", pSpxConnFile));
  137. SpxConnFileDereference (pSpxConnFile, CFREF_DISCWAITSPX);
  138. } else {
  139. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  140. }
  141. return STATUS_PENDING;
  142. }
  143. NTSTATUS
  144. SpxConnClose(
  145. IN PDEVICE Device,
  146. IN PREQUEST Request
  147. )
  148. /*++
  149. Routine Description:
  150. Arguments:
  151. Request - the close request.
  152. Return Value:
  153. STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
  154. request does not point to a real connection
  155. --*/
  156. {
  157. NTSTATUS status;
  158. CTELockHandle lockHandle;
  159. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
  160. // Verify connection file
  161. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  162. {
  163. DBGBRK(FATAL);
  164. return (status);
  165. }
  166. DBGPRINT(CREATE, INFO,
  167. ("SpxConnFileClose: %lx when %lx\n",
  168. pSpxConnFile, pSpxConnFile->scf_RefCount));
  169. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  170. pSpxConnFile->scf_CloseReq = Request;
  171. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
  172. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  173. SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
  174. return STATUS_PENDING;
  175. }
  176. VOID
  177. SpxConnStop(
  178. IN PSPX_CONN_FILE pSpxConnFile
  179. )
  180. /*++
  181. Routine Description:
  182. !!!Connection must have a reference when this is called!!!
  183. Arguments:
  184. Return Value:
  185. --*/
  186. {
  187. CTELockHandle lockHandle;
  188. DBGPRINT(CREATE, INFO,
  189. ("SpxConnFileStop: %lx when %lx.%lx\n",
  190. pSpxConnFile, pSpxConnFile->scf_RefCount,
  191. pSpxConnFile->scf_Flags));
  192. // Call disconnect and disassociate
  193. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  194. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
  195. {
  196. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
  197. if (!SPX_CONN_IDLE(pSpxConnFile))
  198. {
  199. spxConnAbortiveDisc(
  200. pSpxConnFile,
  201. STATUS_LOCAL_DISCONNECT,
  202. SPX_CALL_TDILEVEL,
  203. lockHandle,
  204. FALSE); // [SA] Bug #15249
  205. }
  206. else
  207. {
  208. // Disassociate if we are associated.
  209. spxConnDisAssoc(pSpxConnFile, lockHandle);
  210. }
  211. // Lock released at this point.
  212. }
  213. else
  214. {
  215. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  216. }
  217. return;
  218. }
  219. NTSTATUS
  220. SpxConnAssociate(
  221. IN PDEVICE pDevice,
  222. IN PREQUEST pRequest
  223. )
  224. /*++
  225. Routine Description:
  226. This routine moves the connection from the device list to the inactive
  227. connection list in the address of the address file specified. The address
  228. file is pointed to by the connection and is referenced for the associate.
  229. Arguments:
  230. Return Value:
  231. --*/
  232. {
  233. NTSTATUS status;
  234. PSPX_ADDR_FILE pSpxAddrFile;
  235. CTELockHandle lockHandle1, lockHandle2;
  236. BOOLEAN derefAddr = FALSE, derefConn = FALSE;
  237. PFILE_OBJECT pFileObj = NULL;
  238. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  239. HANDLE AddrObjHandle =
  240. ((PTDI_REQUEST_KERNEL_ASSOCIATE)(REQUEST_PARAMETERS(pRequest)))->AddressHandle;
  241. do
  242. {
  243. // Get the handle to the address object from the irp and map it to
  244. // the corres. file object.
  245. status = ObReferenceObjectByHandle(
  246. AddrObjHandle,
  247. 0,
  248. *IoFileObjectType,
  249. pRequest->RequestorMode,
  250. (PVOID *)&pFileObj,
  251. NULL);
  252. if (!NT_SUCCESS(status))
  253. break;
  254. if (pFileObj->DeviceObject != SpxDevice->dev_DevObj || pFileObj->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE ) {
  255. ObDereferenceObject(pFileObj);
  256. status = STATUS_INVALID_HANDLE;
  257. break;
  258. }
  259. pSpxAddrFile = pFileObj->FsContext;
  260. // ASSERT(pFileObj->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
  261. // Verify address file/connection file
  262. if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS) {
  263. ObDereferenceObject(pFileObj);
  264. break;
  265. }
  266. derefAddr = TRUE;
  267. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS) {
  268. ObDereferenceObject(pFileObj);
  269. break;
  270. }
  271. derefConn = TRUE;
  272. // Grab the addres file lock, then the connection lock for associate.
  273. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle1);
  274. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
  275. if (!SPX_CONN_FLAG(pSpxConnFile, (SPX_CONNFILE_CLOSING |
  276. SPX_CONNFILE_STOPPING |
  277. SPX_CONNFILE_ASSOC))
  278. &&
  279. !(pSpxAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING))
  280. {
  281. derefAddr = FALSE;
  282. SpxAddrFileTransferReference(
  283. pSpxAddrFile, AFREF_VERIFY, AFREF_CONN_ASSOC);
  284. // Queue in the inactive list in the address
  285. pSpxConnFile->scf_Next = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
  286. pSpxAddrFile->saf_Addr->sa_InactiveConnList = pSpxConnFile;
  287. // Queue in the assoc list in the address file
  288. pSpxConnFile->scf_AssocNext = pSpxAddrFile->saf_AssocConnList;
  289. pSpxAddrFile->saf_AssocConnList = pSpxConnFile;
  290. // Remember the addrfile in the connection
  291. pSpxConnFile->scf_AddrFile = pSpxAddrFile;
  292. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
  293. status = STATUS_SUCCESS;
  294. DBGPRINT(CREATE, INFO,
  295. ("SpxConnAssociate: %lx with address file %lx\n",
  296. pSpxConnFile, pSpxAddrFile));
  297. }
  298. else
  299. {
  300. status = STATUS_INVALID_PARAMETER;
  301. }
  302. CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandle2);
  303. CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandle1);
  304. // Dereference the file object corres. to the address object
  305. ObDereferenceObject(pFileObj);
  306. } while (FALSE);
  307. if (derefAddr)
  308. {
  309. SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
  310. }
  311. if (derefConn)
  312. {
  313. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  314. }
  315. return(status);
  316. }
  317. NTSTATUS
  318. SpxConnDisAssociate(
  319. IN PDEVICE pDevice,
  320. IN PREQUEST pRequest
  321. )
  322. /*++
  323. Routine Description:
  324. Arguments:
  325. Return Value:
  326. --*/
  327. {
  328. NTSTATUS status;
  329. CTELockHandle lockHandle;
  330. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  331. // Verify connection file
  332. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  333. return (status);
  334. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  335. if (!SPX_CONN_IDLE(pSpxConnFile)
  336. ||
  337. (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
  338. {
  339. status = STATUS_INVALID_CONNECTION;
  340. }
  341. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  342. // Unlink it if ok.
  343. if (NT_SUCCESS(status))
  344. {
  345. SpxConnStop(pSpxConnFile);
  346. }
  347. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  348. return(status);
  349. }
  350. NTSTATUS
  351. spxConnDisAssoc(
  352. IN PSPX_CONN_FILE pSpxConnFile,
  353. IN CTELockHandle LockHandleConn
  354. )
  355. /*++
  356. Routine Description:
  357. Arguments:
  358. Return Value:
  359. --*/
  360. {
  361. NTSTATUS status = STATUS_SUCCESS;
  362. CTELockHandle lockHandleAddr;
  363. PSPX_ADDR_FILE pSpxAddrFile;
  364. if (SPX_CONN_IDLE(pSpxConnFile)
  365. &&
  366. (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
  367. {
  368. pSpxAddrFile = pSpxConnFile->scf_AddrFile;
  369. }
  370. else
  371. {
  372. status = STATUS_INVALID_CONNECTION;
  373. }
  374. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  375. // Unlink it if ok.
  376. if (NT_SUCCESS(status))
  377. {
  378. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
  379. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  380. // Check again as we had released the lock
  381. if (SPX_CONN_IDLE(pSpxConnFile)
  382. &&
  383. (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
  384. {
  385. pSpxConnFile->scf_AddrFile = NULL;
  386. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
  387. // Dequeue the connection from the address file
  388. spxConnRemoveFromAssocList(
  389. &pSpxAddrFile->saf_AssocConnList,
  390. pSpxConnFile);
  391. // Dequeue the connection file from the address list. It must be
  392. // in the inactive list.
  393. spxConnRemoveFromList(
  394. &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
  395. pSpxConnFile);
  396. }
  397. else
  398. {
  399. status = STATUS_INVALID_CONNECTION;
  400. }
  401. CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
  402. CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
  403. DBGPRINT(CREATE, INFO,
  404. ("SpxConnDisAssociate: %lx from address file %lx\n",
  405. pSpxConnFile, pSpxAddrFile));
  406. if (NT_SUCCESS(status))
  407. {
  408. // Remove reference on address for this association.
  409. SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
  410. }
  411. }
  412. return(status);
  413. }
  414. NTSTATUS
  415. SpxConnConnect(
  416. IN PDEVICE pDevice,
  417. IN PREQUEST pRequest
  418. )
  419. /*++
  420. Routine Description:
  421. Arguments:
  422. We need to have another timer that will be started on the connection
  423. if the tdi client indicated a timeout value. 0 -> we do not start such
  424. a timer, -1 implies, we let our connection timeout values do their thing.
  425. Any other value will forcibly shutdown the connect process, when the timer
  426. fires.
  427. Return Value:
  428. --*/
  429. {
  430. PTDI_REQUEST_KERNEL_CONNECT pParam;
  431. TDI_ADDRESS_IPX UNALIGNED * pTdiAddr;
  432. PNDIS_PACKET pCrPkt;
  433. NTSTATUS status;
  434. PIPXSPX_HDR pIpxSpxHdr;
  435. PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
  436. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  437. PSPX_ADDR pSpxAddr;
  438. BOOLEAN locksHeld = TRUE;
  439. PNDIS_BUFFER NdisBuf, NdisBuf2;
  440. ULONG BufLen =0;
  441. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  442. // Unpack the connect parameters
  443. pParam = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(pRequest);
  444. pTdiAddr= SpxParseTdiAddress(
  445. pParam->RequestConnectionInformation->RemoteAddress);
  446. DBGPRINT(CONNECT, DBG,
  447. ("SpxConnConnect: Remote SOCKET %lx on %lx.%lx\n",
  448. pTdiAddr->Socket,
  449. pSpxConnFile,
  450. pRequest));
  451. // Check if the connection is in a valid state
  452. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  453. {
  454. return(status);
  455. }
  456. do
  457. {
  458. if ((pFindRouteReq =
  459. (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
  460. sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
  461. {
  462. status = STATUS_INSUFFICIENT_RESOURCES;
  463. break;
  464. }
  465. // Check if connection is associated, if so, the association cannot
  466. // go away until the reference above is removed. So we are safe in
  467. // releasing the lock.
  468. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  469. status = STATUS_INVALID_ADDRESS;
  470. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
  471. {
  472. status = STATUS_SUCCESS;
  473. pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
  474. // See if this connection is to be a spx2 connection.
  475. SPX_CONN_RESETFLAG(pSpxConnFile,
  476. (SPX_CONNFILE_SPX2 |
  477. SPX_CONNFILE_NEG |
  478. SPX_CONNFILE_STREAM));
  479. if ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
  480. (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2))
  481. {
  482. DBGPRINT(CONNECT, DBG,
  483. ("SpxConnConnect: SPX2 requested %lx\n",
  484. pSpxConnFile));
  485. SPX_CONN_SETFLAG(
  486. pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
  487. }
  488. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
  489. {
  490. DBGPRINT(CONNECT, DBG,
  491. ("SpxConnConnect: SOCK_STREAM requested %lx\n",
  492. pSpxConnFile));
  493. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
  494. }
  495. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
  496. {
  497. DBGPRINT(CONNECT, ERR,
  498. ("SpxConnConnect: NOACKWAIT requested %lx\n",
  499. pSpxConnFile));
  500. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
  501. }
  502. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
  503. {
  504. DBGPRINT(CONNECT, ERR,
  505. ("spxConnHandleConnReq: IPXHDR requested %lx\n",
  506. pSpxConnFile));
  507. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
  508. }
  509. }
  510. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  511. } while (FALSE);
  512. if (!NT_SUCCESS(status))
  513. {
  514. DBGPRINT(CONNECT, ERR,
  515. ("SpxConnConnect: Failed %lx\n", status));
  516. if (pFindRouteReq)
  517. {
  518. SpxFreeMemory(pFindRouteReq);
  519. }
  520. return(status);
  521. }
  522. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  523. CTEGetLock(&pSpxAddr->sa_Lock, &lockHandleAddr);
  524. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  525. locksHeld = TRUE;
  526. status = STATUS_INVALID_CONNECTION;
  527. if (SPX_CONN_IDLE(pSpxConnFile) &&
  528. ((pSpxConnFile->scf_LocalConnId = spxConnGetId()) != 0))
  529. {
  530. //
  531. // If this was a post-inactivated file, clear the disconnect flags
  532. //
  533. if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  534. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
  535. SPX_DISC_SETSTATE(pSpxConnFile, 0);
  536. }
  537. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_CONNECTING);
  538. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
  539. if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
  540. ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
  541. {
  542. PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
  543. }
  544. pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
  545. // Move connection from inactive list to non-inactive list.
  546. if (!NT_SUCCESS(spxConnRemoveFromList(
  547. &pSpxAddr->sa_InactiveConnList,
  548. pSpxConnFile)))
  549. {
  550. // This should never happen!
  551. KeBugCheck(0);
  552. }
  553. // Put connection in the non-inactive list. Connection id must be set.
  554. SPX_INSERT_ADDR_ACTIVE(
  555. pSpxAddr,
  556. pSpxConnFile);
  557. // Insert in the global connection tree on device
  558. spxConnInsertIntoGlobalActiveList(
  559. pSpxConnFile);
  560. // Store the remote address in the connection.
  561. // !!NOTE!! We get both the network/socket in network form.
  562. *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) =
  563. *((UNALIGNED ULONG *)(&pTdiAddr->NetworkAddress));
  564. RtlCopyMemory(
  565. pSpxConnFile->scf_RemAddr+4,
  566. pTdiAddr->NodeAddress,
  567. 6);
  568. *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10)) =
  569. *((UNALIGNED USHORT *)(&pTdiAddr->Socket));
  570. // Ok, we are all set, build connect packet, queue it into connection
  571. // with the connect request. Ndis buffer already describes this memory
  572. // Build IPX header.
  573. pCrPkt = NULL; // so it knows to allocate one.
  574. SpxPktBuildCr(
  575. pSpxConnFile,
  576. pSpxAddr,
  577. &pCrPkt,
  578. SPX_SENDPKT_IDLE,
  579. SPX2_CONN(pSpxConnFile));
  580. if (pCrPkt != NULL)
  581. {
  582. // Remember the request in the connection
  583. //
  584. // Dont queue for the failure case since we complete it in SpxInternalDispatch.
  585. //
  586. InsertTailList(
  587. &pSpxConnFile->scf_ReqLinkage,
  588. REQUEST_LINKAGE(pRequest));
  589. SpxConnQueueSendPktTail(pSpxConnFile, pCrPkt);
  590. //
  591. // Get the MDL that points to the IPX/SPX header. (the second one)
  592. //
  593. NdisQueryPacket(pCrPkt, NULL, NULL, &NdisBuf, NULL);
  594. NdisGetNextBuffer(NdisBuf, &NdisBuf2);
  595. NdisQueryBufferSafe(NdisBuf2, (PUCHAR) &pIpxSpxHdr, &BufLen, HighPagePriority);
  596. ASSERT(pIpxSpxHdr != NULL); // Can't fail since it is already mapped
  597. #if OWN_PKT_POOLS
  598. pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
  599. NDIS_PACKET_SIZE +
  600. sizeof(SPX_SEND_RESD) +
  601. IpxInclHdrOffset);
  602. #endif
  603. // Initialize the find route request
  604. *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
  605. *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet);
  606. //
  607. // [SA] Bug #15094
  608. // We need to also pass in the node number to IPX so that IPX can
  609. // compare the node addresses to determine the proper WAN NICid
  610. //
  611. // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pIpxSpxHdr->hdr_DestNode, 6) ;
  612. *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
  613. *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNode);
  614. *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
  615. *((UNALIGNED USHORT *)(pIpxSpxHdr->hdr_DestNode+4));
  616. DBGPRINT(CONNECT, DBG,
  617. ("SpxConnConnect: NETWORK %lx\n",
  618. *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet)));
  619. DBGPRINT(CONNECT, DBG,
  620. ("SpxConnConnect: NODE %02x-%02x-%02x-%02x-%02x-%02x\n",
  621. pFindRouteReq->fr_FindRouteReq.Node[0], pFindRouteReq->fr_FindRouteReq.Node[1],
  622. pFindRouteReq->fr_FindRouteReq.Node[2], pFindRouteReq->fr_FindRouteReq.Node[3],
  623. pFindRouteReq->fr_FindRouteReq.Node[4], pFindRouteReq->fr_FindRouteReq.Node[5]));
  624. pFindRouteReq->fr_FindRouteReq.Identifier = IDENTIFIER_SPX;
  625. pFindRouteReq->fr_Ctx = pSpxConnFile;
  626. // We wont force a rip for every connection. Only if its not
  627. // in the IPX database.
  628. pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
  629. // Reference for the find route. So that abort connect wont
  630. // free up the connection until we return from here.
  631. SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
  632. status = STATUS_PENDING;
  633. }
  634. else
  635. {
  636. // Abort connect attempt.
  637. spxConnAbortConnect(
  638. pSpxConnFile,
  639. status,
  640. lockHandleDev,
  641. lockHandleAddr,
  642. lockHandleConn);
  643. CTEAssert(pSpxConnFile->scf_ConnectReq == NULL);
  644. locksHeld = FALSE;
  645. status = STATUS_INSUFFICIENT_RESOURCES;
  646. }
  647. }
  648. if (locksHeld)
  649. {
  650. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  651. CTEFreeLock(&pSpxAddr->sa_Lock, lockHandleAddr);
  652. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  653. }
  654. if (NT_SUCCESS(status))
  655. {
  656. // Start off the find route request, We send the packet in completion.
  657. // The verify reference is kept until the connect request completes.
  658. // If connecting to network 0 we don't do this, proceed to find
  659. // route completion which will send the request on very card.
  660. if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
  661. SpxFindRouteComplete(
  662. &pFindRouteReq->fr_FindRouteReq,
  663. TRUE);
  664. } else {
  665. (*IpxFindRoute)(
  666. &pFindRouteReq->fr_FindRouteReq);
  667. }
  668. }
  669. else
  670. {
  671. DBGPRINT(CONNECT, ERR,
  672. ("SpxConnConnect: Failed %lx\n", status));
  673. SpxFreeMemory(pFindRouteReq);
  674. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  675. }
  676. return(status);
  677. }
  678. NTSTATUS
  679. SpxConnListen(
  680. IN PDEVICE pDevice,
  681. IN PREQUEST pRequest
  682. )
  683. /*++
  684. Routine Description:
  685. Arguments:
  686. We assume the connection passed in is already associated with an address.
  687. If it is not, we will die! Is that ok?
  688. Return Value:
  689. --*/
  690. {
  691. NTSTATUS status;
  692. CTELockHandle lockHandle1, lockHandle2;
  693. PSPX_ADDR pSpxAddr;
  694. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  695. // Check if the connection is in a valid state
  696. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  697. {
  698. return(status);
  699. }
  700. // Check if connection is associated, if so, the association cannot
  701. // go away until the reference above is removed. So we are safe in
  702. // releasing the lock.
  703. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
  704. status = STATUS_INVALID_ADDRESS;
  705. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
  706. {
  707. status = STATUS_SUCCESS;
  708. pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
  709. // See if this connection is to be a spx2 connection.
  710. SPX_CONN_RESETFLAG(pSpxConnFile,
  711. (SPX_CONNFILE_SPX2 |
  712. SPX_CONNFILE_NEG |
  713. SPX_CONNFILE_STREAM));
  714. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2)
  715. {
  716. SPX_CONN_SETFLAG(
  717. pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
  718. }
  719. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
  720. {
  721. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
  722. }
  723. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
  724. {
  725. DBGPRINT(CONNECT, ERR,
  726. ("SpxConnConnect: NOACKWAIT requested %lx\n",
  727. pSpxConnFile));
  728. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
  729. }
  730. if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
  731. {
  732. DBGPRINT(CONNECT, ERR,
  733. ("spxConnHandleConnReq: IPXHDR requested %lx\n",
  734. pSpxConnFile));
  735. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
  736. }
  737. }
  738. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
  739. if (NT_SUCCESS(status))
  740. {
  741. CTEGetLock(&pSpxAddr->sa_Lock, &lockHandle1);
  742. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
  743. status = STATUS_INVALID_CONNECTION;
  744. if (SPX_CONN_IDLE(pSpxConnFile))
  745. {
  746. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
  747. // Move connection from inactive list to listening list.
  748. if (NT_SUCCESS(spxConnRemoveFromList(
  749. &pSpxAddr->sa_InactiveConnList,
  750. pSpxConnFile)))
  751. {
  752. // Put connection in the listening list.
  753. SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile);
  754. InsertTailList(
  755. &pSpxConnFile->scf_ReqLinkage,
  756. REQUEST_LINKAGE(pRequest));
  757. status = STATUS_PENDING;
  758. }
  759. else
  760. {
  761. // This should never happen!
  762. KeBugCheck(0);
  763. }
  764. }
  765. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
  766. CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle1);
  767. }
  768. if (!NT_SUCCESS(status))
  769. {
  770. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  771. }
  772. return(status);
  773. }
  774. NTSTATUS
  775. SpxConnAccept(
  776. IN PDEVICE pDevice,
  777. IN PREQUEST pRequest
  778. )
  779. /*++
  780. Routine Description:
  781. Arguments:
  782. Return Value:
  783. --*/
  784. {
  785. PSPX_ADDR pSpxAddr;
  786. NTSTATUS status;
  787. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  788. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  789. DBGPRINT(CONNECT, DBG,
  790. ("SpxConnAccept: %lx\n", pSpxConnFile));
  791. // Check if the connection is in a valid state
  792. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  793. {
  794. return (status);
  795. }
  796. // Check if we are in the correct state and associated.
  797. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  798. status = STATUS_INVALID_CONNECTION;
  799. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
  800. {
  801. status = STATUS_SUCCESS;
  802. pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
  803. }
  804. CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
  805. if (NT_SUCCESS(status))
  806. {
  807. // Grab all three locks
  808. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  809. CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
  810. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  811. status = STATUS_INVALID_CONNECTION;
  812. if ((SPX_CONN_LISTENING(pSpxConnFile)) &&
  813. (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_RECDREQ))
  814. {
  815. InsertTailList(
  816. &pSpxConnFile->scf_ReqLinkage,
  817. REQUEST_LINKAGE(pRequest));
  818. // Call acceptcr now.
  819. spxConnAcceptCr(
  820. pSpxConnFile,
  821. pSpxAddr,
  822. lockHandleDev,
  823. lockHandleAddr,
  824. lockHandleConn);
  825. DBGPRINT(CONNECT, DBG,
  826. ("SpxConnAccept: Accepted\n"));
  827. status = STATUS_PENDING;
  828. }
  829. else
  830. {
  831. // Free all locks.
  832. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  833. CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  834. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  835. }
  836. }
  837. // Remove reference. Note: Listen reference will exist if ok. And that will
  838. // be transferred to the fact that the connection is active when accepted.
  839. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  840. return(status);
  841. }
  842. NTSTATUS
  843. SpxConnDisconnect(
  844. IN PDEVICE pDevice,
  845. IN PREQUEST pRequest
  846. )
  847. /*++
  848. Routine Description:
  849. If active, we do the following.
  850. If informative disconnect, just remember the request in the connection.
  851. We do not ref for request. Assume it will always be checked for when
  852. changing from disconnect to idle.
  853. Arguments:
  854. Return Value:
  855. --*/
  856. {
  857. PTDI_REQUEST_KERNEL_DISCONNECT pParam;
  858. NTSTATUS status;
  859. CTELockHandle lockHandleConn;
  860. BOOLEAN lockHeld;
  861. SPX_SENDREQ_TYPE reqType;
  862. int numDerefs = 0;
  863. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  864. pParam = (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
  865. // Check if the connection is in a valid state
  866. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  867. {
  868. return(status);
  869. }
  870. // Deref unless the disc request gets queued in as a send request.
  871. numDerefs++;
  872. DBGPRINT(CONNECT, DBG,
  873. ("spxConnDisconnect: %lx On %lx when %lx.%lx %lx Params %lx\n",
  874. pRequest, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile),
  875. SPX_DISC_STATE(pSpxConnFile),
  876. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC),
  877. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC),
  878. pParam->RequestFlags));
  879. DBGPRINT(CONNECT, DBG,
  880. ("SpxConnDisconnect: %lx\n", pSpxConnFile));
  881. // Check if we are in the correct state and associated.
  882. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  883. lockHeld = TRUE;
  884. switch (pParam->RequestFlags)
  885. {
  886. case TDI_DISCONNECT_WAIT:
  887. // If informative disconnect, just remember in the connection.
  888. status = STATUS_INVALID_CONNECTION;
  889. if (!SPX_CONN_IDLE(pSpxConnFile))
  890. {
  891. InsertTailList(
  892. &pSpxConnFile->scf_DiscLinkage,
  893. REQUEST_LINKAGE(pRequest));
  894. status = STATUS_PENDING;
  895. }
  896. break;
  897. case TDI_DISCONNECT_ABORT:
  898. case TDI_DISCONNECT_RELEASE:
  899. // NOTE! We don't honor the async disconnect symantics of tdi
  900. // but map them to an abortive disconnect.
  901. // NOTE! If our send list is not empty but our client tries to
  902. // do a orderly release, we just queue the ord rel as a send
  903. // data request. In process ack, we check for the next packet
  904. // to not be a ord rel before giving up on window closure.
  905. // NOTE! For spx1 connection, map TDI_DISCONNECT_RELEASE to
  906. // TDI_DISCONNECT_ABORT (Informed disconnect)
  907. if (!SPX2_CONN(pSpxConnFile))
  908. {
  909. pParam->RequestFlags = TDI_DISCONNECT_ABORT;
  910. }
  911. switch (SPX_MAIN_STATE(pSpxConnFile))
  912. {
  913. case SPX_CONNFILE_ACTIVE:
  914. // Since we are not a timer disconnect, then we need to keep
  915. // retrying the disconnect packet. Change state to DISCONN if this
  916. // is not an orderly release or we previously received an orderly
  917. // release and are now confirming it.
  918. // Retry timer will now keep sending out the disconnect packet.
  919. reqType = SPX_REQ_DISC;
  920. if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
  921. {
  922. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_ORDREL);
  923. reqType = SPX_REQ_ORDREL;
  924. }
  925. else
  926. {
  927. // Abortive disconnect
  928. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
  929. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_IDISC);
  930. numDerefs++;
  931. spxConnAbortSends(
  932. pSpxConnFile,
  933. STATUS_LOCAL_DISCONNECT,
  934. SPX_CALL_TDILEVEL,
  935. lockHandleConn);
  936. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  937. // Abort all receives if we are informed disconnect.
  938. spxConnAbortRecvs(
  939. pSpxConnFile,
  940. STATUS_LOCAL_DISCONNECT,
  941. SPX_CALL_TDILEVEL,
  942. lockHandleConn);
  943. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  944. // Since we released the lock, a remote IDISC could have come
  945. // in in which case we really don't want to queue in the disc
  946. // request. Instead, we set it as the disc request in the
  947. // connection if one is not already there.
  948. if (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_IDISC)
  949. {
  950. DBGPRINT(CONNECT, ERR,
  951. ("SpxConnDisconnect: DISC not POST! %lx.%lx\n",
  952. pSpxConnFile, SPX_DISC_STATE(pSpxConnFile)));
  953. InsertTailList(
  954. &pSpxConnFile->scf_DiscLinkage,
  955. REQUEST_LINKAGE(pRequest));
  956. status = STATUS_PENDING;
  957. break;
  958. }
  959. }
  960. // !NOTE
  961. // AbortSends might leave send requests around as packets might
  962. // have been with ipx at the time. That is why SendComplete should
  963. // never call AbortSends but must call AbortPkt else it may complete
  964. // the following disconnect request prematurely.
  965. // Creation reference for request.
  966. REQUEST_INFORMATION(pRequest) = 1;
  967. // If we have no current requests, queue it in and
  968. // set it to be the current request, else just queue it in.
  969. // There may be other pending requests in queue.
  970. if (pSpxConnFile->scf_ReqPkt == NULL)
  971. {
  972. pSpxConnFile->scf_ReqPkt = pRequest;
  973. pSpxConnFile->scf_ReqPktOffset = 0;
  974. pSpxConnFile->scf_ReqPktSize = 0;
  975. pSpxConnFile->scf_ReqPktType = reqType;
  976. }
  977. InsertTailList(
  978. &pSpxConnFile->scf_ReqLinkage,
  979. REQUEST_LINKAGE(pRequest));
  980. // Do not deref the connection, it is taken by the pending request
  981. numDerefs--;
  982. // We packetize only upto the window we have.
  983. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
  984. {
  985. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
  986. SpxConnPacketize(
  987. pSpxConnFile,
  988. TRUE,
  989. lockHandleConn);
  990. lockHeld = FALSE;
  991. }
  992. status = STATUS_PENDING;
  993. break;
  994. case SPX_CONNFILE_CONNECTING:
  995. case SPX_CONNFILE_LISTENING:
  996. spxConnAbortiveDisc(
  997. pSpxConnFile,
  998. STATUS_INSUFFICIENT_RESOURCES,
  999. SPX_CALL_TDILEVEL,
  1000. lockHandleConn,
  1001. FALSE); // [SA] Bug #15249
  1002. lockHeld = FALSE;
  1003. status = STATUS_SUCCESS;
  1004. break;
  1005. case SPX_CONNFILE_DISCONN:
  1006. // When we queue in a disconnect as a send request, we expect
  1007. // to be able to set it into the scf_DiscReq when it is done.
  1008. // So we don't use scf_DiscReq here. This will be a problem if
  1009. // the client has a InformDiscReq pending, and a remote disconnect
  1010. // comes in, *and* the client then does a disc. We will be completing
  1011. // the request with STATUS_INVALID_CONNECTION.
  1012. status = STATUS_INVALID_CONNECTION;
  1013. if (pParam->RequestFlags != TDI_DISCONNECT_RELEASE)
  1014. {
  1015. InsertTailList(
  1016. &pSpxConnFile->scf_DiscLinkage,
  1017. REQUEST_LINKAGE(pRequest));
  1018. status = STATUS_PENDING;
  1019. //
  1020. // If this is a disconnect for a connection which was already
  1021. // disconnected (but AFD's disconnect handler was not called
  1022. // because the connfile could not be placed in the inactive list),
  1023. // set this flag so that the disconnect is not called from
  1024. // ConnInactivate now that the disconnect has occured here.
  1025. //
  1026. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC)) {
  1027. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
  1028. }
  1029. //
  1030. // If this was an SPXI connection where we indicated TDI_DISCONNECT_RELEASE
  1031. // to AFD, the ref count was bumped up to indicate a wait for local disconnect
  1032. // from AFD. Now that we have this disconnect, deref the connection file. Now
  1033. // we are ready to truly inactivate this connection file.
  1034. //
  1035. if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
  1036. CTEAssert( (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
  1037. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
  1038. CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
  1039. SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
  1040. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  1041. lockHeld = FALSE;
  1042. SpxConnFileDereference(pSpxConnFile, CFREF_DISCWAITSPX);
  1043. }
  1044. }
  1045. break;
  1046. default:
  1047. // Should never happen!
  1048. status = STATUS_INVALID_CONNECTION;
  1049. }
  1050. break;
  1051. default:
  1052. status = STATUS_INVALID_PARAMETER;
  1053. break;
  1054. }
  1055. if (lockHeld)
  1056. {
  1057. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  1058. }
  1059. DBGPRINT(CONNECT, INFO,
  1060. ("SpxConnDisconnect: returning for %lx.%lx\n", pSpxConnFile, status));
  1061. while (numDerefs-- > 0)
  1062. {
  1063. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1064. }
  1065. return(status);
  1066. }
  1067. NTSTATUS
  1068. SpxConnSend(
  1069. IN PDEVICE pDevice,
  1070. IN PREQUEST pRequest
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. Arguments:
  1075. Return Value:
  1076. --*/
  1077. {
  1078. PTDI_REQUEST_KERNEL_SEND pParam;
  1079. NTSTATUS status;
  1080. CTELockHandle lockHandleConn;
  1081. BOOLEAN lockHeld;
  1082. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  1083. pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
  1084. // Check if the connection is in a valid state
  1085. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  1086. {
  1087. return(status);
  1088. }
  1089. DBGPRINT(SEND, DBG,
  1090. ("SpxConnSend: %lx.%lx.%lx.%lx\n",
  1091. pSpxConnFile, pRequest, pParam->SendLength, pParam->SendFlags));
  1092. // Check if we are in the correct state and associated.
  1093. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  1094. lockHeld = TRUE;
  1095. DBGPRINT(SEND, INFO,
  1096. ("Send: %lx.%lx.%lx\n",
  1097. pParam->SendLength, pParam->SendFlags, pRequest));
  1098. status = STATUS_PENDING;
  1099. do
  1100. {
  1101. if (SPX_CONN_ACTIVE(pSpxConnFile) &&
  1102. ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_ORDREL) &&
  1103. (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL) &&
  1104. (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED)))
  1105. {
  1106. // Creation reference for request.
  1107. REQUEST_INFORMATION(pRequest) = 1;
  1108. // If we have no current requests, queue it in and
  1109. // set it to be the current request, else just queue it in.
  1110. // There may be other pending requests in queue.
  1111. if (pSpxConnFile->scf_ReqPkt == NULL)
  1112. {
  1113. DBGPRINT(SEND, INFO,
  1114. ("%lx\n",
  1115. pRequest));
  1116. pSpxConnFile->scf_ReqPkt = pRequest;
  1117. pSpxConnFile->scf_ReqPktOffset = 0;
  1118. pSpxConnFile->scf_ReqPktSize = pParam->SendLength;
  1119. pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
  1120. pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
  1121. }
  1122. InsertTailList(
  1123. &pSpxConnFile->scf_ReqLinkage,
  1124. REQUEST_LINKAGE(pRequest));
  1125. }
  1126. else
  1127. {
  1128. //
  1129. // [SA] Bug #14655
  1130. // Return the correct error message in case a send fails due to remote disconnect
  1131. //
  1132. if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  1133. ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
  1134. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
  1135. {
  1136. status = STATUS_REMOTE_DISCONNECT ;
  1137. }
  1138. else
  1139. {
  1140. status = STATUS_INVALID_CONNECTION;
  1141. }
  1142. break;
  1143. }
  1144. // We packetize only upto the window we have.
  1145. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
  1146. {
  1147. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
  1148. SpxConnPacketize(pSpxConnFile, TRUE, lockHandleConn);
  1149. lockHeld = FALSE;
  1150. }
  1151. } while (FALSE);
  1152. if (lockHeld)
  1153. {
  1154. CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
  1155. }
  1156. if (!NT_SUCCESS(status))
  1157. {
  1158. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1159. }
  1160. return(status);
  1161. }
  1162. NTSTATUS
  1163. SpxConnRecv(
  1164. IN PDEVICE pDevice,
  1165. IN PREQUEST pRequest
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. Arguments:
  1170. Return Value:
  1171. --*/
  1172. {
  1173. NTSTATUS status;
  1174. CTELockHandle lockHandle;
  1175. BOOLEAN fLockHeld;
  1176. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  1177. // Check if the connection is in a valid state
  1178. if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  1179. {
  1180. return(status);
  1181. }
  1182. DBGPRINT(CONNECT, DBG,
  1183. ("SpxConnReceive: %lx.%lx\n", pSpxConnFile, pRequest));
  1184. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1185. fLockHeld = TRUE;
  1186. status = STATUS_INVALID_CONNECTION;
  1187. if (SPX_CONN_ACTIVE(pSpxConnFile) &&
  1188. !(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)))
  1189. {
  1190. status = STATUS_PENDING;
  1191. // This routine adds its own reference.
  1192. SpxConnQueueRecv(pSpxConnFile, pRequest);
  1193. // If recv pkt queue is non-empty then we have buffered data. Call
  1194. // process pkts/receives.
  1195. if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) ||
  1196. (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED))
  1197. {
  1198. SpxRecvProcessPkts(pSpxConnFile, lockHandle);
  1199. fLockHeld = FALSE;
  1200. }
  1201. }
  1202. if (fLockHeld)
  1203. {
  1204. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  1205. }
  1206. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1207. return(status);
  1208. }
  1209. NTSTATUS
  1210. SpxConnAction(
  1211. IN PDEVICE pDevice,
  1212. IN PREQUEST pRequest
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. Arguments:
  1217. Return Value:
  1218. --*/
  1219. {
  1220. NTSTATUS Status;
  1221. UINT BufferLength;
  1222. UINT DataLength;
  1223. PNDIS_BUFFER NdisBuffer;
  1224. PNWLINK_ACTION NwlinkAction;
  1225. CTELockHandle lockHandle;
  1226. PIPX_SPXCONNSTATUS_DATA pGetStats;
  1227. PSPX_CONN_FILE pSpxConnFile = NULL;
  1228. PSPX_ADDR_FILE pSpxAddrFile = NULL;
  1229. static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
  1230. //
  1231. // To maintain some compatibility with the NWLINK streams-
  1232. // based transport, we use the streams header format for
  1233. // our actions. The old transport expected the action header
  1234. // to be in InputBuffer and the output to go in OutputBuffer.
  1235. // We follow the TDI spec, which states that OutputBuffer
  1236. // is used for both input and output. Since IOCTL_TDI_ACTION
  1237. // is method out direct, this means that the output buffer
  1238. // is mapped by the MDL chain; for action the chain will
  1239. // only have one piece so we use it for input and output.
  1240. //
  1241. NdisBuffer = REQUEST_NDIS_BUFFER(pRequest);
  1242. if (NdisBuffer == NULL)
  1243. {
  1244. return STATUS_INVALID_PARAMETER;
  1245. }
  1246. NdisQueryBufferSafe(
  1247. REQUEST_NDIS_BUFFER(pRequest), (PVOID *)&NwlinkAction, &BufferLength, LowPagePriority);
  1248. if (NwlinkAction == NULL)
  1249. {
  1250. return(STATUS_INSUFFICIENT_RESOURCES);
  1251. }
  1252. // Make sure we have enough room for just the header not
  1253. // including the data.
  1254. if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0])))
  1255. {
  1256. DBGPRINT(ACTION, ERR,
  1257. ("Nwlink action failed, buffer too small\n"));
  1258. return STATUS_BUFFER_TOO_SMALL;
  1259. }
  1260. if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
  1261. (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
  1262. (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
  1263. (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
  1264. return STATUS_NOT_SUPPORTED;
  1265. }
  1266. DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
  1267. // Make sure that the correct file object is being used.
  1268. switch (NwlinkAction->OptionType)
  1269. {
  1270. case NWLINK_OPTION_CONNECTION:
  1271. if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_CONNECTION_FILE)
  1272. {
  1273. DBGPRINT(ACTION, ERR,
  1274. ("Nwlink action failed, not connection file\n"));
  1275. return STATUS_INVALID_HANDLE;
  1276. }
  1277. pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  1278. if ((Status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
  1279. return(Status);
  1280. break;
  1281. case NWLINK_OPTION_ADDRESS:
  1282. if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
  1283. {
  1284. DBGPRINT(ACTION, ERR,
  1285. ("Nwlink action failed, not address file\n"));
  1286. return STATUS_INVALID_HANDLE;
  1287. }
  1288. pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
  1289. if ((Status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
  1290. return(Status);
  1291. break;
  1292. default:
  1293. DBGPRINT(ACTION, ERR,
  1294. ("Nwlink action failed, option type %d\n",
  1295. NwlinkAction->OptionType));
  1296. return STATUS_INVALID_HANDLE;
  1297. }
  1298. // Handle the requests based on the action code. For these
  1299. // requests ActionHeader->ActionCode is 0, we use the
  1300. // Option field in the streams header instead.
  1301. Status = STATUS_SUCCESS;
  1302. DBGPRINT(ACTION, INFO,
  1303. ("SpxConnAction: Option %x\n", NwlinkAction->Option));
  1304. switch (NwlinkAction->Option)
  1305. {
  1306. //
  1307. // This first group support the winsock helper dll.
  1308. // In most cases the corresponding sockopt is shown in
  1309. // the comment, as well as the contents of the Data
  1310. // part of the action buffer.
  1311. //
  1312. case MSPX_SETDATASTREAM:
  1313. if (pSpxConnFile == NULL)
  1314. {
  1315. Status = STATUS_INVALID_HANDLE;
  1316. break;
  1317. }
  1318. if (DataLength >= 1)
  1319. {
  1320. DBGPRINT(ACTION, INFO,
  1321. ("%lx: MIPX_SETSENDPTYPE %x\n",
  1322. pSpxConnFile, NwlinkAction->Data[0]));
  1323. pSpxConnFile->scf_DataType = NwlinkAction->Data[0];
  1324. }
  1325. else
  1326. {
  1327. Status = STATUS_BUFFER_TOO_SMALL;
  1328. }
  1329. break;
  1330. case MSPX_SENDHEADER:
  1331. DBGPRINT(ACTION, INFO,
  1332. ("%lx: MSPX_SENDHEADER\n", pSpxAddrFile));
  1333. if (pSpxAddrFile == NULL)
  1334. {
  1335. Status = STATUS_INVALID_HANDLE;
  1336. break;
  1337. }
  1338. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
  1339. pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_IPXHDR;
  1340. CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
  1341. break ;
  1342. case MSPX_NOSENDHEADER:
  1343. DBGPRINT(ACTION, INFO,
  1344. ("%lx: MSPX_NOSENDHEADER\n", pSpxAddrFile));
  1345. if (pSpxAddrFile == NULL)
  1346. {
  1347. Status = STATUS_INVALID_HANDLE;
  1348. break;
  1349. }
  1350. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
  1351. pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_IPXHDR;
  1352. CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
  1353. break;
  1354. case MSPX_GETSTATS:
  1355. DBGPRINT(ACTION, INFO,
  1356. ("%lx: MSPX_GETSTATS\n", pSpxConnFile));
  1357. if (pSpxConnFile == NULL)
  1358. {
  1359. Status = STATUS_INVALID_HANDLE;
  1360. DBGPRINT(ACTION, INFO,
  1361. ("pSpxConnFile is NULL. %lx: MSPX_GETSTATS\n", pSpxConnFile));
  1362. break;
  1363. }
  1364. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1365. if (!SPX_CONN_IDLE(pSpxConnFile))
  1366. {
  1367. USHORT TempRetryCount;
  1368. //
  1369. // Status fields are returned in network order.
  1370. //
  1371. pGetStats = (PIPX_SPXCONNSTATUS_DATA)&NwlinkAction->Data[0];
  1372. switch (SPX_MAIN_STATE(pSpxConnFile)) {
  1373. case SPX_CONNFILE_LISTENING: pGetStats->ConnectionState = 1; break;
  1374. case SPX_CONNFILE_CONNECTING: pGetStats->ConnectionState = 2; break;
  1375. case SPX_CONNFILE_ACTIVE: pGetStats->ConnectionState = 3; break;
  1376. case SPX_CONNFILE_DISCONN: pGetStats->ConnectionState = 4; break;
  1377. default: pGetStats->ConnectionState = 0;
  1378. }
  1379. pGetStats->WatchDogActive = 1; // Always 1
  1380. GETSHORT2SHORT( // scf_LocalConnId is in host order
  1381. &pGetStats->LocalConnectionId,
  1382. &pSpxConnFile->scf_LocalConnId);
  1383. pGetStats->RemoteConnectionId = pSpxConnFile->scf_RemConnId;
  1384. GETSHORT2SHORT(&pGetStats->LocalSequenceNumber, &pSpxConnFile->scf_SendSeqNum);
  1385. GETSHORT2SHORT(&pGetStats->LocalAckNumber, &pSpxConnFile->scf_RecvSeqNum);
  1386. GETSHORT2SHORT(&pGetStats->LocalAllocNumber, &pSpxConnFile->scf_SentAllocNum);
  1387. GETSHORT2SHORT(&pGetStats->RemoteAckNumber, &pSpxConnFile->scf_RecdAckNum);
  1388. GETSHORT2SHORT(&pGetStats->RemoteAllocNumber, &pSpxConnFile->scf_RecdAllocNum);
  1389. pGetStats->LocalSocket = pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket;
  1390. RtlZeroMemory(pGetStats->ImmediateAddress, 6);
  1391. // Remote network returned in net order.
  1392. *((ULONG UNALIGNED *)pGetStats->RemoteNetwork) =
  1393. *((ULONG UNALIGNED *)pSpxConnFile->scf_RemAddr);
  1394. RtlCopyMemory(
  1395. pGetStats->RemoteNode,
  1396. &pSpxConnFile->scf_RemAddr[4],
  1397. 6);
  1398. pGetStats->RemoteSocket = *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10));
  1399. TempRetryCount = (USHORT)pSpxConnFile->scf_WRetryCount;
  1400. GETSHORT2SHORT(&pGetStats->RetransmissionCount, &TempRetryCount);
  1401. GETSHORT2SHORT(&pGetStats->EstimatedRoundTripDelay, &pSpxConnFile->scf_BaseT1);
  1402. pGetStats->RetransmittedPackets = 0;
  1403. pGetStats->SuppressedPacket = 0;
  1404. DBGPRINT(ACTION, INFO,
  1405. ("SSeq %lx RSeq %lx RecdAck %lx RemAllocNum %lx\n",
  1406. pGetStats->LocalSequenceNumber,
  1407. pGetStats->LocalAckNumber,
  1408. pGetStats->RemoteAckNumber,
  1409. pGetStats->RemoteAllocNumber));
  1410. DBGPRINT(ACTION, INFO,
  1411. ("LocalSkt %lx RemSkt %lx LocConnId %lx RemConnId %lx\n",
  1412. pGetStats->LocalSocket,
  1413. pGetStats->RemoteSocket,
  1414. pGetStats->LocalConnectionId,
  1415. pGetStats->RemoteConnectionId));
  1416. }
  1417. else
  1418. {
  1419. Status = STATUS_INVALID_CONNECTION;
  1420. }
  1421. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  1422. break;
  1423. case MSPX_NOACKWAIT:
  1424. DBGPRINT(ACTION, ERR,
  1425. ("%lx: MSPX_NOACKWAIT\n", pSpxAddrFile));
  1426. if (pSpxAddrFile == NULL)
  1427. {
  1428. Status = STATUS_INVALID_HANDLE;
  1429. break;
  1430. }
  1431. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
  1432. pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_NOACKWAIT;
  1433. CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
  1434. break;
  1435. case MSPX_ACKWAIT:
  1436. DBGPRINT(ACTION, ERR,
  1437. ("%lx: MSPX_ACKWAIT\n", pSpxAddrFile));
  1438. if (pSpxAddrFile == NULL)
  1439. {
  1440. Status = STATUS_INVALID_HANDLE;
  1441. break;
  1442. }
  1443. CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
  1444. pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_NOACKWAIT;
  1445. CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
  1446. break;
  1447. //
  1448. // These are new for ISN (not supported in NWLINK).
  1449. //
  1450. // The Option was not supported, so fail.
  1451. default:
  1452. Status = STATUS_NOT_SUPPORTED;
  1453. break;
  1454. } // end of the long switch on NwlinkAction->Option
  1455. #if DBG
  1456. if (Status != STATUS_SUCCESS) {
  1457. DBGPRINT(ACTION, ERR,
  1458. ("Nwlink action %lx failed, status %lx\n",
  1459. NwlinkAction->Option, Status));
  1460. }
  1461. #endif
  1462. if (pSpxConnFile)
  1463. {
  1464. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1465. }
  1466. if (pSpxAddrFile)
  1467. {
  1468. SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
  1469. }
  1470. return Status;
  1471. }
  1472. VOID
  1473. SpxConnConnectFindRouteComplete(
  1474. IN PSPX_CONN_FILE pSpxConnFile,
  1475. IN PSPX_FIND_ROUTE_REQUEST pFrReq,
  1476. IN BOOLEAN FoundRoute,
  1477. IN CTELockHandle LockHandle
  1478. )
  1479. /*++
  1480. Routine Description:
  1481. This routine is called with the connection lock held and the conn refd.
  1482. It should deal with both.
  1483. Arguments:
  1484. Return Value:
  1485. --*/
  1486. {
  1487. PNDIS_PACKET pCrPkt;
  1488. PSPX_SEND_RESD pSendResd;
  1489. ULONG Timeout;
  1490. NTSTATUS status = STATUS_BAD_NETWORK_PATH;
  1491. pSendResd = pSpxConnFile->scf_SendListHead;
  1492. if (pSendResd == NULL) {
  1493. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
  1494. // Remove the reference for the call.
  1495. SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
  1496. return;
  1497. }
  1498. pCrPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1499. pSendResd, NDIS_PACKET, ProtocolReserved);
  1500. DBGPRINT(CONNECT, INFO,
  1501. ("SpxConnConnectFindRouteComplete: %lx.%d\n",
  1502. pSpxConnFile, FoundRoute));
  1503. #if defined(_PNP_POWER)
  1504. Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
  1505. #else
  1506. if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
  1507. // Here we are going to send on every NIC ID. We adjust the
  1508. // timeout down so that a full run through all the NIC IDs will
  1509. // take one normal timeout. We don't adjust the timer below
  1510. // 100 ms however.
  1511. Timeout = (PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR) / SpxDevice->dev_Adapters;
  1512. if (Timeout < (HALFSEC_TO_MS_FACTOR/5)) {
  1513. Timeout = HALFSEC_TO_MS_FACTOR / 5;
  1514. }
  1515. } else {
  1516. Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
  1517. }
  1518. #endif
  1519. // Timeout value is in half-seconds
  1520. if ((FoundRoute) &&
  1521. ((pSpxConnFile->scf_CTimerId =
  1522. SpxTimerScheduleEvent(
  1523. spxConnConnectTimer,
  1524. Timeout,
  1525. pSpxConnFile)) != 0))
  1526. {
  1527. // Add a reference for the connect timer
  1528. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1529. // If the mac address in local target is all zeros, fill it with our
  1530. // destination address. Also if this is a connect to network 0 fill
  1531. // it in with the destination address, and further down we will loop
  1532. // through all possible NIC IDs.
  1533. if (((*((UNALIGNED ULONG *)
  1534. (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress)) == (ULONG)0)
  1535. &&
  1536. (*((UNALIGNED USHORT *)
  1537. (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
  1538. ||
  1539. (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0))
  1540. {
  1541. DBGPRINT(CONNECT, INFO,
  1542. ("SpxConnConnectFindRouteComplete: LOCAL NET\n"));
  1543. RtlCopyMemory(
  1544. pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
  1545. pSpxConnFile->scf_RemAddr+4,
  1546. 6);
  1547. }
  1548. // We are all set to go ahead with the connect.
  1549. // Timer is started on connection
  1550. status = STATUS_SUCCESS;
  1551. #if defined(_PNP_POWER)
  1552. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
  1553. #else
  1554. if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
  1555. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT) * SpxDevice->dev_Adapters;
  1556. } else {
  1557. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
  1558. }
  1559. #endif _PNP_POWER
  1560. SPX_CONN_SETFLAG(pSpxConnFile,
  1561. (SPX_CONNFILE_C_TIMER | SPX_CONNECT_SENTREQ));
  1562. pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
  1563. pSpxConnFile->scf_AckLocalTarget= pFrReq->fr_FindRouteReq.LocalTarget;
  1564. if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
  1565. #if defined(_PNP_POWER)
  1566. pSpxConnFile->scf_LocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
  1567. pSpxConnFile->scf_AckLocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
  1568. #else
  1569. pSpxConnFile->scf_LocalTarget.NicId = 1;
  1570. pSpxConnFile->scf_AckLocalTarget.NicId = 1;
  1571. #endif _PNP_POWER
  1572. }
  1573. // We will be giving the packet to ipx.
  1574. pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
  1575. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
  1576. // Send the packet
  1577. SPX_SENDPACKET(pSpxConnFile, pCrPkt, pSendResd);
  1578. }
  1579. if (!NT_SUCCESS(status))
  1580. {
  1581. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  1582. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
  1583. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  1584. CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
  1585. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  1586. DBGPRINT(CONNECT, ERR,
  1587. ("SpxConnConnectFindRouteComplete: FAILED on %lx.%d\n",
  1588. pSpxConnFile, FoundRoute));
  1589. spxConnAbortConnect(
  1590. pSpxConnFile,
  1591. status,
  1592. lockHandleDev,
  1593. lockHandleAddr,
  1594. lockHandleConn);
  1595. }
  1596. // Remove the reference for the call.
  1597. SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
  1598. return;
  1599. }
  1600. VOID
  1601. SpxConnActiveFindRouteComplete(
  1602. IN PSPX_CONN_FILE pSpxConnFile,
  1603. IN PSPX_FIND_ROUTE_REQUEST pFrReq,
  1604. IN BOOLEAN FoundRoute,
  1605. IN CTELockHandle LockHandle
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. This routine is called with the connection lock held and the conn refd.
  1610. It should deal with both.
  1611. Arguments:
  1612. Return Value:
  1613. --*/
  1614. {
  1615. BOOLEAN fDisconnect = TRUE;
  1616. SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
  1617. DBGPRINT(CONNECT, DBG,
  1618. ("SpxConnActiveFindRouteComplete: %lx.%lx\n",
  1619. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  1620. // If we are disconnecting, just remove the reference and exit.
  1621. if (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE)
  1622. {
  1623. fDisconnect = FALSE;
  1624. // We are here if either the wdog or the retry timer did a find
  1625. // route. We need to save the info from the find route if it was
  1626. // successful and just restart the timers.
  1627. if (FoundRoute)
  1628. {
  1629. // If the mac address in local target is all zeros, fill it with our
  1630. // destination address.
  1631. if ((*((UNALIGNED ULONG *)
  1632. (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
  1633. &&
  1634. (*((UNALIGNED USHORT *)
  1635. (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
  1636. {
  1637. DBGPRINT(CONNECT, INFO,
  1638. ("SpxConnActiveFindRouteComplete: LOCAL NET\n"));
  1639. RtlCopyMemory(
  1640. pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
  1641. pSpxConnFile->scf_RemAddr+4,
  1642. 6);
  1643. }
  1644. pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
  1645. }
  1646. // Depending on state restart the wdog or retry timer. Add reference
  1647. // for it.
  1648. switch (SPX_SEND_STATE(pSpxConnFile))
  1649. {
  1650. case SPX_SEND_RETRY:
  1651. // Set state to SPX_SEND_RETRYWD
  1652. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRYWD);
  1653. // Start retry timer.
  1654. if ((pSpxConnFile->scf_RTimerId =
  1655. SpxTimerScheduleEvent(
  1656. spxConnRetryTimer,
  1657. pSpxConnFile->scf_BaseT1,
  1658. pSpxConnFile)) != 0)
  1659. {
  1660. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
  1661. // Reference connection for the timer
  1662. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1663. }
  1664. else
  1665. {
  1666. fDisconnect = TRUE;
  1667. }
  1668. break;
  1669. case SPX_SEND_WD:
  1670. // Start watchdog timer.
  1671. if ((pSpxConnFile->scf_WTimerId =
  1672. SpxTimerScheduleEvent(
  1673. spxConnWatchdogTimer,
  1674. PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
  1675. pSpxConnFile)) != 0)
  1676. {
  1677. // Reference connection for the timer
  1678. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1679. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  1680. }
  1681. else
  1682. {
  1683. fDisconnect = TRUE;
  1684. }
  1685. break;
  1686. case SPX_SEND_IDLE:
  1687. case SPX_SEND_PACKETIZE:
  1688. // Do nothing, remove reference and leave.
  1689. break;
  1690. default:
  1691. KeBugCheck(0);
  1692. }
  1693. }
  1694. if (fDisconnect)
  1695. {
  1696. DBGPRINT(CONNECT, DBG1,
  1697. ("SpxConnActiveFindRouteComplete: DISCONNECT %lx.%lx\n",
  1698. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  1699. // Abortive disc will reset the funky state if necessary.
  1700. spxConnAbortiveDisc(
  1701. pSpxConnFile,
  1702. STATUS_INSUFFICIENT_RESOURCES,
  1703. SPX_CALL_TDILEVEL,
  1704. LockHandle,
  1705. FALSE); // [SA] Bug #15249
  1706. }
  1707. else
  1708. {
  1709. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
  1710. }
  1711. SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
  1712. return;
  1713. }
  1714. ULONG
  1715. spxConnConnectTimer(
  1716. IN PVOID Context,
  1717. IN BOOLEAN TimerShuttingDown
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. We enter this routine during the connection attempt. We could be at any
  1722. stage of sending either the CR or the SN packet. If we have reached the end of
  1723. the retry count, we need to know the substate at that point. For a CR, we give
  1724. up trying to connect, and for a SN we try the next lower packet size or if we
  1725. have reached the minimum packet size, we give up the connect.
  1726. Arguments:
  1727. Return Value:
  1728. --*/
  1729. {
  1730. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
  1731. PNDIS_PACKET pPkt;
  1732. PSPX_SEND_RESD pSendResd;
  1733. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  1734. BOOLEAN fAbort = FALSE, locksHeld = FALSE, sendPkt = FALSE;
  1735. PREQUEST pRequest = NULL;
  1736. // Get all locks
  1737. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  1738. CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
  1739. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  1740. locksHeld = TRUE;
  1741. DBGPRINT(CONNECT, INFO,
  1742. ("spxConnConnectTimer: Entered\n"));
  1743. do
  1744. {
  1745. if ((!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER)) ||
  1746. (!SPX_CONN_CONNECTING(pSpxConnFile) &&
  1747. !SPX_CONN_LISTENING(pSpxConnFile)))
  1748. {
  1749. TimerShuttingDown = TRUE;
  1750. }
  1751. if (TimerShuttingDown)
  1752. {
  1753. break;
  1754. }
  1755. if (SPX_CONN_CONNECTING(pSpxConnFile))
  1756. {
  1757. switch (SPX_CONNECT_STATE(pSpxConnFile))
  1758. {
  1759. case SPX_CONNECT_SENTREQ:
  1760. // There should be only one packet in list, the cr.
  1761. CTEAssert(pSpxConnFile->scf_SendListHead ==
  1762. pSpxConnFile->scf_SendListTail);
  1763. pSendResd = pSpxConnFile->scf_SendListHead;
  1764. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1765. pSendResd,
  1766. NDIS_PACKET,
  1767. ProtocolReserved);
  1768. if (pSpxConnFile->scf_CRetryCount-- == 0)
  1769. {
  1770. // No luck, we need to complete connect request with failure
  1771. ++SpxDevice->dev_Stat.NotFoundFailures;
  1772. fAbort = TRUE;
  1773. break;
  1774. }
  1775. // We need to resend the packet
  1776. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
  1777. {
  1778. // Try next time.
  1779. break;
  1780. }
  1781. pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
  1782. sendPkt = TRUE;
  1783. break;
  1784. case SPX_CONNECT_NEG:
  1785. if (!spxConnGetPktByType(
  1786. pSpxConnFile,
  1787. SPX_TYPE_SN,
  1788. FALSE,
  1789. &pPkt))
  1790. {
  1791. KeBugCheck(0);
  1792. }
  1793. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  1794. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
  1795. {
  1796. // Try when we come in next.
  1797. break;
  1798. }
  1799. // If we have exhausted current retries, try next smaller size.
  1800. // If this was the smallest size, we abort.
  1801. if (pSpxConnFile->scf_CRetryCount-- == 0)
  1802. {
  1803. // Have we tried the smallest size?
  1804. CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
  1805. if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
  1806. {
  1807. // Give up! Remove negotiate packet etc.
  1808. ++SpxDevice->dev_Stat.SessionTimeouts;
  1809. fAbort = TRUE;
  1810. break;
  1811. }
  1812. // Set neg pkt size to new lower size
  1813. spxConnSetNegSize(
  1814. pPkt,
  1815. pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
  1816. pSpxConnFile->scf_CRetryCount =
  1817. PARAM(CONFIG_CONNECTION_COUNT);
  1818. }
  1819. // We need to resend the packet
  1820. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
  1821. pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
  1822. sendPkt = TRUE;
  1823. break;
  1824. case SPX_CONNECT_W_SETUP:
  1825. default:
  1826. DBGPRINT(CONNECT, ERR,
  1827. ("spxConnConnectTimer: state is W_Setup %lx\n",
  1828. pSpxConnFile));
  1829. KeBugCheck(0);
  1830. }
  1831. }
  1832. else
  1833. {
  1834. switch (SPX_LISTEN_STATE(pSpxConnFile))
  1835. {
  1836. case SPX_LISTEN_SETUP:
  1837. if (!spxConnGetPktByType(
  1838. pSpxConnFile,
  1839. SPX_TYPE_SS,
  1840. FALSE,
  1841. &pPkt))
  1842. {
  1843. KeBugCheck(0);
  1844. }
  1845. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  1846. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
  1847. {
  1848. // Try when we come in next.
  1849. break;
  1850. }
  1851. // If we have exhausted current retries, try next smaller size.
  1852. // If this was the smallest size, we abort.
  1853. if (pSpxConnFile->scf_CRetryCount-- == 0)
  1854. {
  1855. // Have we tried the smallest size?
  1856. if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
  1857. {
  1858. // Give up! Remove negotiate packet etc. Have an abort
  1859. // kind of routine.
  1860. ++SpxDevice->dev_Stat.SessionTimeouts;
  1861. fAbort = TRUE;
  1862. break;
  1863. }
  1864. // Set neg pkt size to new lower size
  1865. spxConnSetNegSize(
  1866. pPkt,
  1867. pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
  1868. pSpxConnFile->scf_CRetryCount =
  1869. PARAM(CONFIG_CONNECTION_COUNT);
  1870. }
  1871. // We need to resend the packet
  1872. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
  1873. pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
  1874. sendPkt = TRUE;
  1875. break;
  1876. default:
  1877. KeBugCheck(0);
  1878. }
  1879. }
  1880. } while (FALSE);
  1881. if (fAbort)
  1882. {
  1883. CTEAssert(!sendPkt);
  1884. DBGPRINT(CONNECT, ERR,
  1885. ("spxConnConnectTimer: Expired for %lx\n", pSpxConnFile));
  1886. spxConnAbortConnect(
  1887. pSpxConnFile,
  1888. STATUS_BAD_NETWORK_PATH,
  1889. lockHandleDev,
  1890. lockHandleAddr,
  1891. lockHandleConn);
  1892. locksHeld = FALSE;
  1893. }
  1894. if (locksHeld)
  1895. {
  1896. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  1897. CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  1898. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  1899. }
  1900. if (sendPkt)
  1901. {
  1902. CTEAssert(!fAbort);
  1903. #if !defined(_PNP_POWER)
  1904. if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
  1905. (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)) {
  1906. // we are sending to all NICs because this is the initial
  1907. // connect frame and the remote network is 0.
  1908. pSpxConnFile->scf_LocalTarget.NicId = (USHORT)
  1909. ((pSpxConnFile->scf_LocalTarget.NicId % SpxDevice->dev_Adapters) + 1);
  1910. // we pass this a valid packet in pPkt, so it knows to
  1911. // just refresh the header and not update the protocol
  1912. // reserved variables.
  1913. SpxPktBuildCr(
  1914. pSpxConnFile,
  1915. pSpxConnFile->scf_AddrFile->saf_Addr,
  1916. &pPkt,
  1917. 0, // state will not be updated
  1918. SPX2_CONN(pSpxConnFile));
  1919. }
  1920. #endif !_PNP_POWER
  1921. // Send the packet
  1922. SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
  1923. }
  1924. if (TimerShuttingDown || fAbort)
  1925. {
  1926. // Dereference connection for verify done in connect, for timer. This
  1927. // should complete any pending disconnects if they had come in in the
  1928. // meantime.
  1929. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1930. return(TIMER_DONT_REQUEUE);
  1931. }
  1932. return(TIMER_REQUEUE_CUR_VALUE);
  1933. }
  1934. ULONG
  1935. spxConnWatchdogTimer(
  1936. IN PVOID Context,
  1937. IN BOOLEAN TimerShuttingDown
  1938. )
  1939. /*++
  1940. Routine Description:
  1941. This is started on a connection right after the CR or the CR ack is received.
  1942. During the connection establishment phase, it does nothing other than decrement
  1943. the retry count and upon reaching 0, it aborts the connection. When it goes off
  1944. and finds the connection is active, it sends a probe.
  1945. Arguments:
  1946. Return Value:
  1947. --*/
  1948. {
  1949. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
  1950. CTELockHandle lockHandle;
  1951. PSPX_SEND_RESD pSendResd;
  1952. PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
  1953. PNDIS_PACKET pProbe = NULL;
  1954. BOOLEAN lockHeld, fSpx2 = SPX2_CONN(pSpxConnFile),
  1955. fDisconnect = FALSE, fFindRoute = FALSE, fSendProbe = FALSE;
  1956. DBGPRINT(CONNECT, INFO,
  1957. ("spxConnWatchdogTimer: Entered\n"));
  1958. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1959. lockHeld = TRUE;
  1960. do
  1961. {
  1962. if (TimerShuttingDown ||
  1963. (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER)) ||
  1964. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
  1965. {
  1966. #if DBG
  1967. if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
  1968. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
  1969. {
  1970. CTEAssert(FALSE);
  1971. }
  1972. #endif
  1973. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  1974. TimerShuttingDown = TRUE;
  1975. break;
  1976. }
  1977. // If the retry timer is active on this connection, and the watchdog
  1978. // timer happens to fire, just requeue ourselves for spx2. For spx1,
  1979. // we go ahead with sending a probe. Retry timer does the same things
  1980. // watchdog does for spx2.
  1981. switch (SPX_MAIN_STATE(pSpxConnFile))
  1982. {
  1983. case SPX_CONNFILE_ACTIVE:
  1984. case SPX_CONNFILE_DISCONN:
  1985. // Squash the race condition where a disconnect request is never
  1986. // packetized, because the send state was not IDLE.
  1987. if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC)
  1988. {
  1989. DBGPRINT(CONNECT, ERR,
  1990. ("spxConnWatchdogTimer: POST IDISC %lx\n",
  1991. pSpxConnFile));
  1992. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
  1993. {
  1994. DBGPRINT(CONNECT, ERR,
  1995. ("spxConnWatchdogTimer: PKT POST IDISC %lx\n",
  1996. pSpxConnFile));
  1997. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
  1998. SpxConnPacketize(
  1999. pSpxConnFile,
  2000. TRUE,
  2001. lockHandle);
  2002. lockHeld = FALSE;
  2003. break;
  2004. }
  2005. }
  2006. if (!fSpx2)
  2007. {
  2008. if (pSpxConnFile->scf_WRetryCount-- > 0)
  2009. {
  2010. fSendProbe = TRUE;
  2011. }
  2012. else
  2013. {
  2014. fDisconnect = TRUE;
  2015. }
  2016. break;
  2017. }
  2018. // SPX2 connection. Watchdog algorithm needs to do lots of goody
  2019. // stuff. If retry is active, just requeue ourselves.
  2020. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
  2021. break;
  2022. // There is a race between watchdog and retry if its started. Who
  2023. // ever changes the state first gets to go do its thing.
  2024. switch (SPX_SEND_STATE(pSpxConnFile))
  2025. {
  2026. case SPX_SEND_IDLE:
  2027. // Enter WD state only if we fired for the second time witout
  2028. // an ack. This prevents PACKETIZE from blocking due to being
  2029. // in a non-idle state.
  2030. CTEAssert(pSpxConnFile->scf_WRetryCount != 0);
  2031. if ((pSpxConnFile->scf_WRetryCount)-- !=
  2032. (LONG)PARAM(CONFIG_KEEPALIVE_COUNT))
  2033. {
  2034. // We enter the WD state. Build and send a probe.
  2035. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_WD);
  2036. SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
  2037. }
  2038. fSendProbe = TRUE;
  2039. break;
  2040. case SPX_SEND_PACKETIZE:
  2041. // Do nothing.
  2042. break;
  2043. case SPX_SEND_RETRY:
  2044. case SPX_SEND_RETRYWD:
  2045. case SPX_SEND_RENEG:
  2046. case SPX_SEND_RETRY2:
  2047. case SPX_SEND_RETRY3:
  2048. // Do nothing. Send timer got in first.
  2049. DBGPRINT(CONNECT, DBG1,
  2050. ("SpxConnWDogTimer: When retry fired %lx\n",
  2051. pSpxConnFile));
  2052. break;
  2053. case SPX_SEND_WD:
  2054. // Decrement count. If not zero, send a probe. If half the
  2055. // count is reached, stop timer and call find route.
  2056. if (pSpxConnFile->scf_WRetryCount-- > 0)
  2057. {
  2058. if (pSpxConnFile->scf_WRetryCount !=
  2059. (LONG)PARAM(CONFIG_KEEPALIVE_COUNT)/2)
  2060. {
  2061. fSendProbe = TRUE;
  2062. break;
  2063. }
  2064. if ((pFindRouteReq =
  2065. (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
  2066. sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
  2067. {
  2068. fDisconnect = TRUE;
  2069. break;
  2070. }
  2071. // Remove timer reference/ Add find route request ref
  2072. fFindRoute = TRUE;
  2073. TimerShuttingDown = TRUE;
  2074. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  2075. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
  2076. SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
  2077. // Initialize the find route request
  2078. *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network) =
  2079. *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
  2080. //
  2081. // [SA] Bug #15094
  2082. // We need to also pass in the node number to IPX so that IPX can
  2083. // compare the node addresses to determine the proper WAN NICid
  2084. //
  2085. // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6);
  2086. *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
  2087. *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
  2088. *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
  2089. *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
  2090. DBGPRINT(CONNECT, DBG,
  2091. ("SpxConnWDogTimer: NETWORK %lx\n",
  2092. *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
  2093. pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
  2094. pFindRouteReq->fr_Ctx = pSpxConnFile;
  2095. // Make sure we have IPX re-rip.
  2096. pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
  2097. }
  2098. else
  2099. {
  2100. fDisconnect = TRUE;
  2101. }
  2102. break;
  2103. default:
  2104. KeBugCheck(0);
  2105. }
  2106. break;
  2107. case SPX_CONNFILE_CONNECTING:
  2108. if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) ||
  2109. (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_NEG))
  2110. {
  2111. // Do nothing. Connect timer is active.
  2112. DBGPRINT(CONNECT, ERR,
  2113. ("SpxConnWDogTimer: CR Timer active %lx\n",
  2114. pSpxConnFile));
  2115. break;
  2116. }
  2117. if (!(pSpxConnFile->scf_WRetryCount--))
  2118. {
  2119. // Disconnect!
  2120. DBGPRINT(CONNECT, ERR,
  2121. ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
  2122. pSpxConnFile->scf_LocalConnId, pSpxConnFile));
  2123. fDisconnect = TRUE;
  2124. }
  2125. break;
  2126. case SPX_CONNFILE_LISTENING:
  2127. if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP)
  2128. {
  2129. // Do nothing. Connect timer is active.
  2130. DBGPRINT(CONNECT, ERR,
  2131. ("SpxConnWDogTimer: CR Timer active %lx\n",
  2132. pSpxConnFile));
  2133. break;
  2134. }
  2135. if (!(pSpxConnFile->scf_WRetryCount--))
  2136. {
  2137. // Disconnect!
  2138. DBGPRINT(CONNECT, ERR,
  2139. ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
  2140. pSpxConnFile->scf_LocalConnId, pSpxConnFile));
  2141. fDisconnect = TRUE;
  2142. }
  2143. break;
  2144. default:
  2145. // Should never happen!
  2146. KeBugCheck(0);
  2147. }
  2148. } while (FALSE);
  2149. if (fSendProbe)
  2150. {
  2151. CTEAssert(lockHeld);
  2152. CTEAssert(!fDisconnect);
  2153. DBGPRINT(CONNECT, DBG1,
  2154. ("spxConnWatchdogTimer: Send Probe from %lx.%lx\n",
  2155. pSpxConnFile->scf_LocalConnId, pSpxConnFile));
  2156. // Build a probe and send it out to the remote end.
  2157. SpxPktBuildProbe(
  2158. pSpxConnFile,
  2159. &pProbe,
  2160. (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
  2161. fSpx2);
  2162. if (pProbe != NULL)
  2163. {
  2164. SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
  2165. pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
  2166. }
  2167. }
  2168. if (fDisconnect)
  2169. {
  2170. CTEAssert(lockHeld);
  2171. CTEAssert(!fSendProbe);
  2172. // Disconnect!
  2173. DBGPRINT(CONNECT, ERR,
  2174. ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
  2175. pSpxConnFile->scf_LocalConnId, pSpxConnFile));
  2176. TimerShuttingDown = TRUE;
  2177. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  2178. // If spx2, check if we need to do anything special.
  2179. // AbortiveDisc will reset funky state if needed.
  2180. spxConnAbortiveDisc(
  2181. pSpxConnFile,
  2182. STATUS_LINK_TIMEOUT,
  2183. SPX_CALL_TDILEVEL,
  2184. lockHandle,
  2185. FALSE); // [SA] Bug #15249
  2186. lockHeld = FALSE;
  2187. }
  2188. if (lockHeld)
  2189. {
  2190. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  2191. }
  2192. if (fFindRoute)
  2193. {
  2194. CTEAssert(!fSendProbe);
  2195. CTEAssert(!fDisconnect);
  2196. CTEAssert(TimerShuttingDown);
  2197. // Start off the find route request
  2198. (*IpxFindRoute)(
  2199. &pFindRouteReq->fr_FindRouteReq);
  2200. }
  2201. if (pProbe != NULL)
  2202. {
  2203. // Send the packet
  2204. SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
  2205. }
  2206. if (TimerShuttingDown)
  2207. {
  2208. // Dereference connection for verify done in connect, for timer. This
  2209. // should complete any pending disconnects if they had come in in the
  2210. // meantime.
  2211. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2212. }
  2213. return((TimerShuttingDown ? TIMER_DONT_REQUEUE : TIMER_REQUEUE_CUR_VALUE));
  2214. }
  2215. ULONG
  2216. spxConnRetryTimer(
  2217. IN PVOID Context,
  2218. IN BOOLEAN TimerShuttingDown
  2219. )
  2220. /*++
  2221. Routine Description:
  2222. Arguments:
  2223. Return Value:
  2224. --*/
  2225. {
  2226. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
  2227. PSPX_SEND_RESD pSendResd;
  2228. CTELockHandle lockHandleConn;
  2229. PIPXSPX_HDR pSendHdr;
  2230. PNDIS_PACKET pPkt;
  2231. PNDIS_PACKET pProbe = NULL;
  2232. PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
  2233. // Compiler warning reenqueueTime = pSpxConnFile->scf_BaseT1; [tingcai]
  2234. // USHORT reenqueueTime = TIMER_REQUEUE_CUR_VALUE;
  2235. UINT reenqueueTime = TIMER_REQUEUE_CUR_VALUE;
  2236. BOOLEAN lockHeld, fResendPkt = FALSE, fDisconnect = FALSE,
  2237. fFindRoute = FALSE, fBackoffTimer = FALSE;
  2238. PREQUEST pRequest = NULL;
  2239. PNDIS_BUFFER NdisBuf, NdisBuf2;
  2240. ULONG BufLen = 0;
  2241. DBGPRINT(CONNECT, INFO,
  2242. ("spxConnRetryTimer: Entered\n"));
  2243. // Get lock
  2244. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  2245. lockHeld = TRUE;
  2246. do
  2247. {
  2248. // If timer is not up, no send pkts, just return.
  2249. if (TimerShuttingDown ||
  2250. (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)) ||
  2251. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
  2252. ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL))
  2253. {
  2254. #if DBG
  2255. if ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL)
  2256. {
  2257. if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
  2258. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
  2259. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
  2260. {
  2261. CTEAssert(FALSE);
  2262. }
  2263. }
  2264. #endif
  2265. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
  2266. TimerShuttingDown = TRUE;
  2267. break;
  2268. }
  2269. // In all other cases, reenqueue with potentially modified reenqueue
  2270. // time.
  2271. reenqueueTime = pSpxConnFile->scf_BaseT1;
  2272. DBGPRINT(SEND, INFO,
  2273. ("spxConnRetryTimer: BaseT1 %lx on %lx\n",
  2274. pSpxConnFile->scf_BaseT1, pSpxConnFile));
  2275. // If an ack for a packet was processed while we were out, reset
  2276. // retry count and return. Or if we are packetizing, return.
  2277. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)
  2278. {
  2279. break;
  2280. }
  2281. else if ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
  2282. (pSpxConnFile->scf_RetrySeqNum != pSendResd->sr_SeqNum))
  2283. {
  2284. pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
  2285. break;
  2286. }
  2287. // If packet is still with IPX, requeue for next time.
  2288. if (pSendResd->sr_State & SPX_SENDPKT_IPXOWNS)
  2289. {
  2290. break;
  2291. }
  2292. CTEAssert(pSendResd != NULL);
  2293. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  2294. pSendResd, NDIS_PACKET, ProtocolReserved);
  2295. //
  2296. // Get the MDL that points to the IPX/SPX header. (the second one)
  2297. //
  2298. NdisQueryPacket(pPkt, NULL, NULL, &NdisBuf, NULL);
  2299. NdisGetNextBuffer(NdisBuf, &NdisBuf2);
  2300. NdisQueryBufferSafe(NdisBuf2, (PUCHAR) &pSendHdr, &BufLen, LowPagePriority);
  2301. ASSERT(pSendHdr != NULL);
  2302. #if OWN_PKT_POOLS
  2303. pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
  2304. NDIS_PACKET_SIZE +
  2305. sizeof(SPX_SEND_RESD) +
  2306. IpxInclHdrOffset);
  2307. #endif
  2308. switch (SPX_SEND_STATE(pSpxConnFile))
  2309. {
  2310. case SPX_SEND_IDLE:
  2311. // Set ack bit in packet. pSendResd initialized at beginning.
  2312. pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
  2313. // Do we backoff the timer?
  2314. fBackoffTimer =
  2315. (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_REXMIT) != 0);
  2316. // We are going to resend this packet
  2317. pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
  2318. SPX_SENDPKT_ACKREQ |
  2319. SPX_SENDPKT_REXMIT);
  2320. ++SpxDevice->dev_Stat.ResponseTimerExpirations;
  2321. CTEAssert((ULONG)pSpxConnFile->scf_RRetryCount <=
  2322. PARAM(CONFIG_REXMIT_COUNT));
  2323. DBGPRINT(SEND, DBG1,
  2324. ("spxConnRetryTimer: Retry Count %lx on %lx\n",
  2325. pSpxConnFile->scf_RRetryCount, pSpxConnFile));
  2326. fResendPkt = TRUE;
  2327. if (pSpxConnFile->scf_RRetryCount-- != 0)
  2328. {
  2329. // We dont treat the IDISC packet as a data packet, so none
  2330. // of the fancy spx2 retry stuff if we are retrying the idisc.
  2331. if (SPX2_CONN(pSpxConnFile) &&
  2332. (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_IDISC))
  2333. {
  2334. // We enter the RETRY state. Reference conn for this
  2335. // "funky" state.
  2336. CTEAssert(SPX2_CONN(pSpxConnFile));
  2337. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY);
  2338. SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
  2339. }
  2340. }
  2341. else
  2342. {
  2343. DBGPRINT(SEND, ERR,
  2344. ("spxConnRetryTimer: Retry Count over on %lx\n",
  2345. pSpxConnFile));
  2346. fDisconnect = TRUE;
  2347. fResendPkt = FALSE;
  2348. pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
  2349. }
  2350. break;
  2351. case SPX_SEND_RETRY:
  2352. // When we have reached retry_count/2 limit, start locate route. Do
  2353. // not queue ourselves. Handle restarting timer in find route
  2354. // completion. If timer starts successfully in find route comp, then
  2355. // it will change our state to RETRYWD.
  2356. // Decrement count. If half the count is reached, stop timer and call
  2357. // find route.
  2358. if (pSpxConnFile->scf_RRetryCount-- !=
  2359. (LONG)PARAM(CONFIG_REXMIT_COUNT)/2)
  2360. {
  2361. // We are going to resend this packet
  2362. pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
  2363. SPX_SENDPKT_ACKREQ |
  2364. SPX_SENDPKT_REXMIT);
  2365. fResendPkt = TRUE;
  2366. fBackoffTimer = TRUE;
  2367. break;
  2368. }
  2369. if ((pFindRouteReq =
  2370. (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
  2371. sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
  2372. {
  2373. DBGPRINT(SEND, ERR,
  2374. ("spxConnRetryTimer: Alloc Mem %lx\n",
  2375. pSpxConnFile));
  2376. fDisconnect = TRUE;
  2377. break;
  2378. }
  2379. // Remove timer reference/ Add find route request ref
  2380. fFindRoute = TRUE;
  2381. TimerShuttingDown = TRUE;
  2382. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
  2383. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
  2384. SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
  2385. // Initialize the find route request
  2386. *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
  2387. *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
  2388. //
  2389. // [SA] Bug #15094
  2390. // We need to also pass in the node number to IPX so that IPX can
  2391. // compare the node addresses to determine the proper WAN NICid
  2392. //
  2393. // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6) ;
  2394. *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
  2395. *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
  2396. *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4)) =
  2397. *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
  2398. DBGPRINT(CONNECT, DBG,
  2399. ("SpxConnRetryTimer: NETWORK %lx\n",
  2400. *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
  2401. pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
  2402. pFindRouteReq->fr_Ctx = pSpxConnFile;
  2403. // Make sure we have IPX re-rip.
  2404. pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
  2405. break;
  2406. case SPX_SEND_RETRYWD:
  2407. // Retry a watchdog packet WCount times (initialize to RETRY_COUNT).
  2408. // If process ack receives an ack (i.e. actual ack packet) while in
  2409. // this state, it will transition the state to RENEG.
  2410. //
  2411. // If the pending data gets acked while in this state, we go back
  2412. // to idle.
  2413. DBGPRINT(CONNECT, DBG1,
  2414. ("spxConnRetryTimer: Send Probe from %lx.%lx\n",
  2415. pSpxConnFile->scf_LocalConnId, pSpxConnFile));
  2416. // Use watchdog count here.
  2417. if (pSpxConnFile->scf_WRetryCount-- > 0)
  2418. {
  2419. // Build a probe and send it out to the remote end.
  2420. SpxPktBuildProbe(
  2421. pSpxConnFile,
  2422. &pProbe,
  2423. (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
  2424. TRUE);
  2425. if (pProbe != NULL)
  2426. {
  2427. SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
  2428. pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
  2429. break;
  2430. }
  2431. }
  2432. // Just set state to retry data packet retry_count/2 times.
  2433. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  2434. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY2);
  2435. break;
  2436. case SPX_SEND_RENEG:
  2437. // Renegotiate size. If we give up, goto RETRY3.
  2438. // For this both sides must have negotiated size to begin with.
  2439. // If they did not, we go on to retrying the data packet.
  2440. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
  2441. {
  2442. DBGPRINT(SEND, ERR,
  2443. ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
  2444. pSpxConnFile,
  2445. pSpxConnFile->scf_Flags));
  2446. // Reset count to be
  2447. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2448. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
  2449. break;
  2450. }
  2451. // Send reneg packet, if we get the rr ack, then we resend data
  2452. // on queue. Note that each time we goto a new negotiate size,
  2453. // we rebuild the data packets.
  2454. if (pSpxConnFile->scf_RRetryCount-- == 0)
  2455. {
  2456. // Reset count.
  2457. pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
  2458. if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
  2459. (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
  2460. {
  2461. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2462. DBGPRINT(SEND, DBG3,
  2463. ("SpxConnRetryTimer: %lx MIN RENEG SIZE\n",
  2464. pSpxConnFile));
  2465. }
  2466. // Are we at the lowest possible reneg pkt size? If not, try
  2467. // next lower. When we do this, we free all pending send
  2468. // packets and reset the packetize queue to the first packet.
  2469. // Process ack will just do packetize and will not do anything
  2470. // more other than resetting state to proper value.
  2471. DBGPRINT(SEND, DBG3,
  2472. ("spxConnRetryTimer: RENEG: %lx - CURRENT %lx\n",
  2473. pSpxConnFile,
  2474. pSpxConnFile->scf_MaxPktSize));
  2475. if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
  2476. {
  2477. // We tried lowest size and failed to receive ack. Just
  2478. // retry data packet, and disc if no ack.
  2479. DBGPRINT(SEND, DBG3,
  2480. ("spxConnRetryTimer: RENEG(min), RETRY3: %lx - %lx\n",
  2481. pSpxConnFile,
  2482. pSpxConnFile->scf_MaxPktSize));
  2483. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2484. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
  2485. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
  2486. break;
  2487. }
  2488. DBGPRINT(SEND, DBG3,
  2489. ("spxConnRetryTimer: RENEG(!min): %lx - ATTEMPT %lx\n",
  2490. pSpxConnFile,
  2491. pSpxConnFile->scf_MaxPktSize));
  2492. }
  2493. DBGPRINT(SEND, DBG3,
  2494. ("spxConnRetryTimer: %lx.%lx.%lx RENEG SEQNUM %lx ACKNUM %lx\n",
  2495. pSpxConnFile,
  2496. pSpxConnFile->scf_RRetryCount,
  2497. pSpxConnFile->scf_MaxPktSize,
  2498. (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
  2499. pSpxConnFile->scf_SentAllocNum));
  2500. // Use first unused data packet sequence number.
  2501. SpxPktBuildRr(
  2502. pSpxConnFile,
  2503. &pPkt,
  2504. (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
  2505. (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY));
  2506. if (pPkt != NULL)
  2507. {
  2508. SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
  2509. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  2510. fResendPkt = TRUE;
  2511. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
  2512. }
  2513. break;
  2514. case SPX_SEND_RETRY2:
  2515. // Retry the data packet for remaining amount of RRetryCount. If not
  2516. // acked goto cleanup. If ack received while in this state, goto idle.
  2517. if (pSpxConnFile->scf_RRetryCount-- > 0)
  2518. {
  2519. // We are going to resend this packet
  2520. pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
  2521. SPX_SENDPKT_ACKREQ |
  2522. SPX_SENDPKT_REXMIT);
  2523. DBGPRINT(SEND, DBG3,
  2524. ("spxConnRetryTimer: 2nd try Resend on %lx\n",
  2525. pSpxConnFile));
  2526. fResendPkt = TRUE;
  2527. fBackoffTimer = TRUE;
  2528. }
  2529. else
  2530. {
  2531. DBGPRINT(SEND, ERR,
  2532. ("spxConnRetryTimer: Retry Count over on %lx\n",
  2533. pSpxConnFile));
  2534. fDisconnect = TRUE;
  2535. }
  2536. break;
  2537. case SPX_SEND_RETRY3:
  2538. // Send data packet for RETRY_COUNT times initialized in RRetryCount
  2539. // before state changed to this state. If ok, process ack moves us
  2540. // back to PKT/IDLE. If not, we disconnect.
  2541. // We are going to resend this packet
  2542. if (pSpxConnFile->scf_RRetryCount-- > 0)
  2543. {
  2544. DBGPRINT(SEND, DBG3,
  2545. ("spxConnRetryTimer: 3rd try Resend on %lx\n",
  2546. pSpxConnFile));
  2547. // We are going to resend this packet
  2548. pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
  2549. SPX_SENDPKT_ACKREQ |
  2550. SPX_SENDPKT_REXMIT);
  2551. fResendPkt = TRUE;
  2552. fBackoffTimer = TRUE;
  2553. }
  2554. else
  2555. {
  2556. DBGPRINT(SEND, ERR,
  2557. ("spxConnRetryTimer: Retry Count over on %lx\n",
  2558. pSpxConnFile));
  2559. fDisconnect = TRUE;
  2560. }
  2561. break;
  2562. case SPX_SEND_WD:
  2563. // Do nothing. Watchdog timer has fired, just requeue.
  2564. break;
  2565. default:
  2566. KeBugCheck(0);
  2567. }
  2568. if (fBackoffTimer)
  2569. {
  2570. // Increase retransmit timeout by 50% upto maximum indicated by
  2571. // initial retransmission value.
  2572. reenqueueTime += reenqueueTime/2;
  2573. if (reenqueueTime > MAX_RETRY_DELAY)
  2574. reenqueueTime = MAX_RETRY_DELAY;
  2575. pSpxConnFile->scf_BaseT1 =
  2576. pSpxConnFile->scf_AveT1 = reenqueueTime;
  2577. pSpxConnFile->scf_DevT1 = 0;
  2578. DBGPRINT(SEND, DBG,
  2579. ("spxConnRetryTimer: Backed retry on %lx.%lx %lx\n",
  2580. pSpxConnFile, pSendResd->sr_SeqNum, reenqueueTime));
  2581. }
  2582. if (fDisconnect)
  2583. {
  2584. CTEAssert(lockHeld);
  2585. // Do not requeue this timer.
  2586. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
  2587. TimerShuttingDown = TRUE;
  2588. // Disconnect the connection.
  2589. spxConnAbortiveDisc(
  2590. pSpxConnFile,
  2591. STATUS_LINK_TIMEOUT,
  2592. SPX_CALL_TDILEVEL,
  2593. lockHandleConn,
  2594. FALSE); // [SA] Bug #15249
  2595. lockHeld = FALSE;
  2596. }
  2597. } while (FALSE);
  2598. if (lockHeld)
  2599. {
  2600. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  2601. }
  2602. if (fResendPkt)
  2603. {
  2604. DBGPRINT(SEND, DBG,
  2605. ("spxConnRetryTimer: Resend pkt on %lx.%lx\n",
  2606. pSpxConnFile, pSendResd->sr_SeqNum));
  2607. ++SpxDevice->dev_Stat.DataFramesResent;
  2608. ExInterlockedAddLargeStatistic(
  2609. &SpxDevice->dev_Stat.DataFrameBytesResent,
  2610. pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
  2611. SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
  2612. }
  2613. else if (fFindRoute)
  2614. {
  2615. CTEAssert(!fResendPkt);
  2616. CTEAssert(!fDisconnect);
  2617. CTEAssert(TimerShuttingDown);
  2618. DBGPRINT(SEND, DBG3,
  2619. ("spxConnRetryTimer: Find route on %lx\n",
  2620. pSpxConnFile));
  2621. // Start off the find route request
  2622. (*IpxFindRoute)(
  2623. &pFindRouteReq->fr_FindRouteReq);
  2624. }
  2625. else if (pProbe != NULL)
  2626. {
  2627. // Send the packet
  2628. SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
  2629. }
  2630. if (TimerShuttingDown)
  2631. {
  2632. // Dereference connection for verify done in connect, for timer. This
  2633. // should complete any pending disconnects if they had come in in the
  2634. // meantime.
  2635. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2636. reenqueueTime = TIMER_DONT_REQUEUE;
  2637. }
  2638. DBGPRINT(SEND, INFO,
  2639. ("spxConnRetryTimer: Reenqueue time : %lx on %lx\n",
  2640. reenqueueTime, pSpxConnFile));
  2641. return(reenqueueTime);
  2642. }
  2643. ULONG
  2644. spxConnAckTimer(
  2645. IN PVOID Context,
  2646. IN BOOLEAN TimerShuttingDown
  2647. )
  2648. /*++
  2649. Routine Description:
  2650. Arguments:
  2651. Return Value:
  2652. --*/
  2653. {
  2654. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
  2655. CTELockHandle lockHandleConn;
  2656. DBGPRINT(SEND, INFO,
  2657. ("spxConnAckTimer: Entered\n"));
  2658. // Get lock
  2659. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  2660. if (!TimerShuttingDown &&
  2661. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
  2662. {
  2663. // We didnt have any back traffic, until we do a send from this
  2664. // end, send acks immediately. Dont try to piggyback.
  2665. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
  2666. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
  2667. ++SpxDevice->dev_Stat.PiggybackAckTimeouts;
  2668. DBGPRINT(SEND, DBG,
  2669. ("spxConnAckTimer: Send ack on %lx.%lx\n",
  2670. pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
  2671. SpxConnSendAck(pSpxConnFile, lockHandleConn);
  2672. }
  2673. else
  2674. {
  2675. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
  2676. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  2677. }
  2678. // Dereference connection for verify done in connect, for timer. This
  2679. // should complete any pending disconnects if they had come in in the
  2680. // meantime.
  2681. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2682. return(TIMER_DONT_REQUEUE);
  2683. }
  2684. //
  2685. // DISCONNECT ROUTINES
  2686. //
  2687. VOID
  2688. spxConnAbortiveDisc(
  2689. IN PSPX_CONN_FILE pSpxConnFile,
  2690. IN NTSTATUS Status,
  2691. IN SPX_CALL_LEVEL CallLevel,
  2692. IN CTELockHandle LockHandleConn,
  2693. IN BOOLEAN IDiscFlag // [SA] Bug #15249
  2694. )
  2695. /*++
  2696. Routine Description:
  2697. This is called when:
  2698. We time out or have insufficient resources -
  2699. STATUS_LINK_TIMEOUT/STATUS_INSUFFICIENT_RESOURCES
  2700. - We abort everything. Could be from watchdog or retry. Stop both.
  2701. We receive a informed disconnect packet -
  2702. STATUS_REMOTE_DISCONNECT
  2703. - We abort everything. Ack must be sent by caller as an orphan pkt.
  2704. We receive a informed disconnect ack pkt
  2705. STATUS_SUCCESS
  2706. - We abort everything
  2707. - Abort is done with status success (this completes our disc req in
  2708. the send queue)
  2709. NOTE: CALLED UNDER THE CONNECTION LOCK.
  2710. Arguments:
  2711. [SA] Bug #15249: Added IDiscFlag to indicate if this is an Informed Disconnect. If so, indicate
  2712. TDI_DISCONNECT_RELEASE to AFD so it allows a receive of buffered pkts. This flag is TRUE
  2713. only if this routine is called from SpxConnProcessIDisc for SPX connections.
  2714. Return Value:
  2715. --*/
  2716. {
  2717. int numDerefs = 0;
  2718. PVOID pDiscHandlerCtx=NULL;
  2719. PTDI_IND_DISCONNECT pDiscHandler = NULL;
  2720. BOOLEAN lockHeld = TRUE;
  2721. DBGPRINT(CONNECT, DBG,
  2722. ("spxConnAbortiveDisc: %lx - On %lx when %lx\n",
  2723. Status, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  2724. switch (Status) {
  2725. case STATUS_LINK_TIMEOUT: ++SpxDevice->dev_Stat.LinkFailures; break;
  2726. case STATUS_INSUFFICIENT_RESOURCES: ++SpxDevice->dev_Stat.LocalResourceFailures; break;
  2727. case STATUS_REMOTE_DISCONNECT: ++SpxDevice->dev_Stat.RemoteDisconnects; break;
  2728. case STATUS_SUCCESS:
  2729. case STATUS_LOCAL_DISCONNECT: ++SpxDevice->dev_Stat.LocalDisconnects; break;
  2730. }
  2731. switch (SPX_MAIN_STATE(pSpxConnFile))
  2732. {
  2733. case SPX_CONNFILE_ACTIVE:
  2734. // For transition from active to disconn.
  2735. numDerefs++;
  2736. case SPX_CONNFILE_DISCONN:
  2737. // If we are in any state other than idle/packetize,
  2738. // remove the reference for the funky state, and reset the send state to be
  2739. // idle.
  2740. if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
  2741. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE))
  2742. {
  2743. #if DBG
  2744. if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  2745. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
  2746. {
  2747. DBGPRINT(CONNECT, ERR,
  2748. ("spxConnAbortiveDisc: When DISC STATE %lx.%lx\n",
  2749. pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
  2750. }
  2751. #endif
  2752. DBGPRINT(CONNECT, DBG1,
  2753. ("spxConnAbortiveDisc: When SEND ERROR STATE %lx.%lx\n",
  2754. pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
  2755. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  2756. SpxConnFileTransferReference(
  2757. pSpxConnFile,
  2758. CFREF_ERRORSTATE,
  2759. CFREF_VERIFY);
  2760. numDerefs++;
  2761. }
  2762. // This can be called when a idisc is received, or if a timer
  2763. // disconnect is happening, or if we sent a idisc/ordrel, but the retries
  2764. // timed out and we are aborting the connection.
  2765. // So if we are already aborting, never mind.
  2766. //
  2767. // [SA] Bug #15249
  2768. // SPX_DISC_INACTIVATED indicates a DISC_ABORT'ing connection that has been
  2769. // inactivated (connfile removed from active conn. list)
  2770. //
  2771. if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  2772. ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
  2773. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
  2774. {
  2775. break;
  2776. }
  2777. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
  2778. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ABORT);
  2779. // Stop all timers.
  2780. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
  2781. {
  2782. if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
  2783. {
  2784. numDerefs++;
  2785. }
  2786. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
  2787. }
  2788. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
  2789. {
  2790. if (SpxTimerCancelEvent(pSpxConnFile->scf_RTimerId, FALSE))
  2791. {
  2792. numDerefs++;
  2793. }
  2794. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
  2795. }
  2796. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
  2797. {
  2798. if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
  2799. {
  2800. numDerefs++;
  2801. }
  2802. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  2803. }
  2804. #if 0
  2805. //
  2806. // [SA] We need to call AFD after aborting sends since this connection
  2807. // becomes a candidate for re-use as soon as the disconnect handler is
  2808. // called.
  2809. // We call the disconnect handler when the refcount falls to 0 and the
  2810. // connection transitions to the inactive list.
  2811. //
  2812. // NOTE! We indicate disconnect to afd *before* aborting sends to avoid
  2813. // afd from calling us again with a disconnect.
  2814. // Get disconnect handler if we have one. And we have not indicated
  2815. // abortive disconnect on this connection to afd.
  2816. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
  2817. {
  2818. // Yeah, we set the flag regardless of whether a handler is
  2819. // present.
  2820. pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
  2821. pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
  2822. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
  2823. }
  2824. #endif
  2825. //
  2826. // [SA] Save the IDiscFlag in the Connection.
  2827. //
  2828. (IDiscFlag) ?
  2829. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC) :
  2830. SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC);
  2831. // Indicate disconnect to afd.
  2832. if (pDiscHandler != NULL)
  2833. {
  2834. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2835. DBGPRINT(CONNECT, INFO,
  2836. ("spxConnAbortiveDisc: Indicating to afd On %lx when %lx\n",
  2837. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  2838. // First complete all requests waiting for receive completion on
  2839. // this conn before indicating disconnect.
  2840. spxConnCompletePended(pSpxConnFile);
  2841. //
  2842. // [SA] bug #15249
  2843. // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
  2844. //
  2845. if (!IDiscFlag)
  2846. {
  2847. (*pDiscHandler)(
  2848. pDiscHandlerCtx,
  2849. pSpxConnFile->scf_ConnCtx,
  2850. 0, // Disc data
  2851. NULL,
  2852. 0, // Disc info
  2853. NULL,
  2854. TDI_DISCONNECT_ABORT);
  2855. }
  2856. else
  2857. {
  2858. //
  2859. // [SA] bug #15249
  2860. // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
  2861. // it has buffered before the remote disconnect took place.
  2862. //
  2863. (*pDiscHandler)(
  2864. pDiscHandlerCtx,
  2865. pSpxConnFile->scf_ConnCtx,
  2866. 0, // Disc data
  2867. NULL,
  2868. 0, // Disc info
  2869. NULL,
  2870. TDI_DISCONNECT_RELEASE);
  2871. }
  2872. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2873. }
  2874. // Go through and kill all pending requests.
  2875. spxConnAbortRecvs(
  2876. pSpxConnFile,
  2877. Status,
  2878. CallLevel,
  2879. LockHandleConn);
  2880. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2881. spxConnAbortSends(
  2882. pSpxConnFile,
  2883. Status,
  2884. CallLevel,
  2885. LockHandleConn);
  2886. lockHeld = FALSE;
  2887. break;
  2888. case SPX_CONNFILE_CONNECTING:
  2889. case SPX_CONNFILE_LISTENING:
  2890. DBGPRINT(CONNECT, DBG,
  2891. ("spxConnAbortiveDisc: CONN/LIST Disc On %lx when %lx\n",
  2892. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  2893. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2894. lockHeld = FALSE;
  2895. {
  2896. CTELockHandle lockHandleAddr, lockHandleDev;
  2897. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  2898. CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
  2899. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2900. // Ensure we are still in connecting/listening, else call abortive
  2901. // again.
  2902. switch (SPX_MAIN_STATE(pSpxConnFile))
  2903. {
  2904. case SPX_CONNFILE_CONNECTING:
  2905. case SPX_CONNFILE_LISTENING:
  2906. DBGPRINT(CONNECT, DBG,
  2907. ("spxConnAbortiveDisc: CONN/LIST Disc2 On %lx when %lx\n",
  2908. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  2909. spxConnAbortConnect(
  2910. pSpxConnFile,
  2911. Status,
  2912. lockHandleDev,
  2913. lockHandleAddr,
  2914. LockHandleConn);
  2915. break;
  2916. case SPX_CONNFILE_ACTIVE:
  2917. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2918. CTEFreeLock(
  2919. pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  2920. CTEFreeLock(
  2921. &SpxDevice->dev_Lock, lockHandleDev);
  2922. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2923. DBGPRINT(CONNECT, DBG,
  2924. ("spxConnAbortiveDisc: CHG ACT Disc2 On %lx when %lx\n",
  2925. pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
  2926. spxConnAbortiveDisc(
  2927. pSpxConnFile,
  2928. Status,
  2929. CallLevel,
  2930. LockHandleConn,
  2931. FALSE); // [SA] Bug #15249
  2932. break;
  2933. default:
  2934. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2935. CTEFreeLock(
  2936. pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  2937. CTEFreeLock(
  2938. &SpxDevice->dev_Lock, lockHandleDev);
  2939. break;
  2940. }
  2941. }
  2942. default:
  2943. // Already disconnected.
  2944. break;
  2945. }
  2946. if (lockHeld)
  2947. {
  2948. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2949. }
  2950. while (numDerefs-- > 0)
  2951. {
  2952. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2953. }
  2954. return;
  2955. }