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

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