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

4236 lines
171 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxcpkt.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) 14-July-1995
  15. Bug fixes - tagged [SA]
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. // Define module number for event logging entries
  20. #define FILENUM SPXCPKT
  21. VOID
  22. SpxTdiCancel(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp);
  25. NTSTATUS
  26. spxPrepareIrpForCancel(PIRP pIrp)
  27. {
  28. KIRQL oldIrql;
  29. IoAcquireCancelSpinLock(&oldIrql);
  30. CTEAssert(pIrp->CancelRoutine == NULL);
  31. if (!pIrp->Cancel) {
  32. IoMarkIrpPending(pIrp);
  33. // Double check if the routine can handle accept cancel.
  34. IoSetCancelRoutine(pIrp, SpxTdiCancel);
  35. // Do I need to increment any reference count here?
  36. DBGPRINT(CONNECT, INFO,
  37. ("spxPrepareIrpForCancel: Prepare IRP %p for cancel.\n", pIrp));
  38. IoReleaseCancelSpinLock(oldIrql);
  39. return(STATUS_SUCCESS);
  40. }
  41. DBGPRINT(CONNECT, INFO,
  42. ("spxPrepareIrpForCancel: The IRP %p has already been canceled.\n", pIrp));
  43. IoReleaseCancelSpinLock(oldIrql);
  44. pIrp->IoStatus.Status = STATUS_CANCELLED;
  45. pIrp->IoStatus.Information = 0;
  46. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  47. return(STATUS_CANCELLED);
  48. }
  49. VOID
  50. spxConnHandleConnReq(
  51. IN PIPXSPX_HDR pIpxSpxHdr,
  52. IN PIPX_LOCAL_TARGET pRemoteAddr
  53. )
  54. /*++
  55. Routine Description:
  56. Arguments:
  57. Return Value:
  58. --*/
  59. {
  60. BOOLEAN fNeg, fSpx2;
  61. TA_IPX_ADDRESS srcIpxAddr;
  62. PTDI_IND_CONNECT connHandler;
  63. USHORT srcConnId, destConnId, destSkt,
  64. pktLen, seqNum, ackNum, allocNum;
  65. PVOID connHandlerCtx;
  66. PREQUEST pListenReq;
  67. PSPX_SEND_RESD pSendResd;
  68. NTSTATUS status;
  69. CTELockHandle lockHandle, lockHandleDev, lockHandleConn;
  70. CONNECTION_CONTEXT connCtx;
  71. PIRP acceptIrp;
  72. PSPX_ADDR pSpxAddr;
  73. PSPX_ADDR_FILE pSpxAddrFile, pSpxRefFile;
  74. PSPX_CONN_FILE pSpxConnFile;
  75. PNDIS_PACKET pCrAckPkt;
  76. BOOLEAN connectAccepted = FALSE, delayAccept = FALSE,
  77. addrLock = FALSE, tdiListen = FALSE;
  78. // Convert hdr to host format as needed.
  79. GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
  80. GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
  81. GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
  82. GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
  83. GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
  84. // We keep and use the remote id in the net format. This maintains the
  85. // 0x0 and 0xFFFF to be as in the host format.
  86. srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
  87. // Verify Connect Request
  88. if (((pIpxSpxHdr->hdr_ConnCtrl & (SPX_CC_ACK | SPX_CC_SYS)) !=
  89. (SPX_CC_ACK | SPX_CC_SYS)) ||
  90. (pIpxSpxHdr->hdr_DataType != 0) ||
  91. (seqNum != 0) ||
  92. (ackNum != 0) ||
  93. (srcConnId == 0) ||
  94. (srcConnId == 0xFFFF) ||
  95. (destConnId != 0xFFFF))
  96. {
  97. DBGPRINT(RECEIVE, ERR,
  98. ("SpxConnSysPacket: VerifyCR Failed %lx.%lx\n",
  99. srcConnId, destConnId));
  100. return;
  101. }
  102. // Get the destination socket from the header
  103. destSkt = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_DestSkt;
  104. SpxBuildTdiAddress(
  105. &srcIpxAddr,
  106. sizeof(srcIpxAddr),
  107. (PBYTE)pIpxSpxHdr->hdr_SrcNet,
  108. pIpxSpxHdr->hdr_SrcNode,
  109. pIpxSpxHdr->hdr_SrcSkt);
  110. // Ok, get the address object this is destined for.
  111. CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
  112. pSpxAddr = SpxAddrLookup(SpxDevice, destSkt);
  113. CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
  114. if (pSpxAddr == NULL)
  115. {
  116. DBGPRINT(RECEIVE, DBG,
  117. ("SpxReceive: No addr for %lx\n", destSkt));
  118. return;
  119. }
  120. fSpx2 = ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
  121. (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2));
  122. fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
  123. DBGPRINT(CONNECT, DBG,
  124. ("spxConnHandleConnReq: Received connect req! %d.%d\n",
  125. fSpx2, fNeg));
  126. CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
  127. addrLock = TRUE;
  128. // We use a bit setting in the flag to prevent reentering
  129. // per address file.
  130. //
  131. // We first search the list of non-inactive connections on the address
  132. // this packet came in on to see if it is a duplicate. If it is, we just
  133. // resend ack. Note we dont need to scan the global connection list.
  134. status = SpxAddrConnByRemoteIdAddrLock(
  135. pSpxAddr, srcConnId, pIpxSpxHdr->hdr_SrcNet, &pSpxConnFile);
  136. if (NT_SUCCESS(status))
  137. {
  138. DBGPRINT(CONNECT, ERR,
  139. ("spxConnHandleConnReq: Received duplicate connect req! %lx\n",
  140. pSpxConnFile));
  141. if (SPX_CONN_ACTIVE(pSpxConnFile) ||
  142. (SPX_CONN_LISTENING(pSpxConnFile) &&
  143. ((SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK) ||
  144. (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP))))
  145. {
  146. DBGPRINT(CONNECT, ERR,
  147. ("spxConnHandleConnReq: Sending Duplicate CR - ACK! %lx\n",
  148. pSpxConnFile));
  149. // Build and send an ack
  150. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  151. SpxPktBuildCrAck(
  152. pSpxConnFile,
  153. pSpxAddr,
  154. &pCrAckPkt,
  155. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
  156. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG),
  157. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2));
  158. if (pCrAckPkt != NULL)
  159. {
  160. SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
  161. }
  162. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  163. CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
  164. addrLock = FALSE;
  165. // Send the CR Ack packet!
  166. if (pCrAckPkt != NULL)
  167. {
  168. pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
  169. SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
  170. }
  171. }
  172. if (addrLock)
  173. {
  174. CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
  175. // We should return in this if, else addrLock should be set to
  176. // FALSE.
  177. }
  178. // Deref the connection
  179. SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
  180. // Deref the address
  181. SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
  182. return;
  183. }
  184. do
  185. {
  186. // New connection request:
  187. // Assume we will be able to accept it and allocate a packet for the ack.
  188. // Walk list of listening connections if any.
  189. pSpxRefFile = NULL;
  190. if ((pSpxConnFile = pSpxAddr->sa_ListenConnList) != NULL)
  191. {
  192. PTDI_REQUEST_KERNEL_LISTEN pParam;
  193. DBGPRINT(RECEIVE, INFO,
  194. ("SpxConnIndicate: Listen available!\n"));
  195. // dequeue connection
  196. pSpxAddr->sa_ListenConnList = pSpxConnFile->scf_Next;
  197. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  198. CTEAssert(!IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
  199. pListenReq = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
  200. pParam = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(pListenReq);
  201. // if autoaccept, acceptIrp = listenIrp, get connection id and
  202. // process as we do for an indication. As the connection has a
  203. // listen posted on it, it must have a reference for it.
  204. //
  205. // if !autoaccept, we need to complete the listen irp.
  206. delayAccept = (BOOLEAN)((pParam->RequestFlags & TDI_QUERY_ACCEPT) != 0);
  207. if (delayAccept)
  208. {
  209. // Remove the listen irp and prepare for completion.
  210. // NOTE!! Here we do not remove the listen reference. This will
  211. // be removed if disconnect happens, or if accept
  212. // happens, it is transferred to being ref for connection
  213. // being active.
  214. RemoveEntryList(REQUEST_LINKAGE(pListenReq));
  215. REQUEST_STATUS(pListenReq) = STATUS_SUCCESS;
  216. REQUEST_INFORMATION(pListenReq) = 0;
  217. }
  218. // Are we ok with spx2?
  219. if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2)) ||
  220. !fSpx2)
  221. {
  222. // We better use spx only.
  223. SPX_CONN_RESETFLAG(pSpxConnFile,
  224. (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
  225. fSpx2 = fNeg = FALSE;
  226. }
  227. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  228. connectAccepted = TRUE;
  229. tdiListen = TRUE;
  230. }
  231. else
  232. {
  233. // No listens available. Check for connect handlers.
  234. // Walk list of address files indicating to each until accepted.
  235. for (pSpxAddrFile = pSpxAddr->sa_AddrFileList;
  236. pSpxAddrFile != NULL;
  237. pSpxAddrFile = pSpxAddrFile->saf_Next)
  238. {
  239. if ((pSpxAddrFile->saf_Flags & (SPX_ADDRFILE_CLOSING |
  240. SPX_ADDRFILE_CONNIND)) ||
  241. ((connHandler = pSpxAddrFile->saf_ConnHandler) == NULL))
  242. {
  243. continue;
  244. }
  245. // Connect indication in progress, drop all subsequent.
  246. pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_CONNIND;
  247. connHandlerCtx = pSpxAddrFile->saf_ConnHandlerCtx;
  248. SpxAddrFileLockReference(pSpxAddrFile, AFREF_INDICATION);
  249. CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle);
  250. addrLock = FALSE;
  251. if (pSpxRefFile)
  252. {
  253. SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
  254. pSpxRefFile = NULL;
  255. }
  256. // Make the indication. We are always returned an accept irp on
  257. // indication. Else we fail to accept the connection.
  258. status = (*connHandler)(
  259. connHandlerCtx,
  260. sizeof(srcIpxAddr),
  261. (PVOID)&srcIpxAddr,
  262. 0, // User data length
  263. NULL, // User data
  264. 0, // Option length
  265. NULL, // Options
  266. &connCtx,
  267. &acceptIrp);
  268. DBGPRINT(RECEIVE, DBG,
  269. ("SpxConn: indicate status %lx.%lx\n",
  270. status, acceptIrp));
  271. CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
  272. addrLock = TRUE;
  273. pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_CONNIND;
  274. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  275. {
  276. NTSTATUS retStatus;
  277. CTEAssert(acceptIrp != NULL);
  278. retStatus = spxPrepareIrpForCancel(acceptIrp);
  279. if (!NT_SUCCESS(retStatus)) {
  280. // Copy from the failure case below. [TC]
  281. if (acceptIrp)
  282. {
  283. IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
  284. }
  285. pSpxRefFile = pSpxAddrFile;
  286. // Shall we close the connection request and listion object here?
  287. break;
  288. }
  289. // Find the connection and accept the connection using that
  290. // connection object.
  291. SpxConnFileReferenceByCtxLock(
  292. pSpxAddrFile,
  293. connCtx,
  294. &pSpxConnFile,
  295. &status);
  296. if (!NT_SUCCESS(status))
  297. {
  298. // The connection object is closing, or is not found
  299. // in our list. The accept irp must have had the same
  300. // connection object. AFD isnt behaving well.
  301. // KeBugCheck(0);
  302. // The code bugchecked (as commented out above).
  303. // Now, we just return error to the TDI client and return from here.
  304. if (acceptIrp)
  305. {
  306. acceptIrp->IoStatus.Status = STATUS_ADDRESS_NOT_ASSOCIATED;
  307. IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
  308. }
  309. pSpxRefFile = pSpxAddrFile;
  310. break;
  311. }
  312. // Only for debugging.
  313. SpxConnFileTransferReference(
  314. pSpxConnFile,
  315. CFREF_BYCTX,
  316. CFREF_VERIFY);
  317. pListenReq = SpxAllocateRequest(
  318. SpxDevice,
  319. acceptIrp);
  320. IF_NOT_ALLOCATED(pListenReq)
  321. {
  322. acceptIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  323. IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
  324. // Setup for dereference
  325. pSpxRefFile = pSpxAddrFile;
  326. break;
  327. }
  328. InsertTailList(
  329. &pSpxConnFile->scf_ReqLinkage,
  330. REQUEST_LINKAGE(pListenReq));
  331. // Setup for dereference
  332. pSpxRefFile = pSpxAddrFile;
  333. connectAccepted = TRUE;
  334. // See if this connection is to be a spx2 connection.
  335. SPX_CONN_RESETFLAG(pSpxConnFile,
  336. (SPX_CONNFILE_SPX2 |
  337. SPX_CONNFILE_NEG |
  338. SPX_CONNFILE_STREAM));
  339. if ((pSpxAddrFile->saf_Flags & SPX_ADDRFILE_SPX2) && fSpx2)
  340. {
  341. SPX_CONN_SETFLAG(
  342. pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
  343. }
  344. else
  345. {
  346. fSpx2 = fNeg = FALSE;
  347. }
  348. if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
  349. {
  350. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
  351. }
  352. if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
  353. {
  354. DBGPRINT(CONNECT, ERR,
  355. ("spxConnHandleConnReq: NOACKWAIT requested %lx\n",
  356. pSpxConnFile));
  357. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
  358. }
  359. if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
  360. {
  361. DBGPRINT(CONNECT, ERR,
  362. ("spxConnHandleConnReq: IPXHDR requested %lx\n",
  363. pSpxConnFile));
  364. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
  365. }
  366. break;
  367. }
  368. else
  369. {
  370. // We are not going to accept the connection on this address.
  371. // Try next one.
  372. pSpxRefFile = pSpxAddrFile;
  373. continue;
  374. }
  375. }
  376. }
  377. } while (FALSE);
  378. if (addrLock)
  379. {
  380. CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
  381. // No need for flag from this point on.
  382. // addrLock = FALSE;
  383. }
  384. if (pSpxRefFile)
  385. {
  386. SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
  387. pSpxRefFile = NULL;
  388. }
  389. if (connectAccepted)
  390. {
  391. CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
  392. CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
  393. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  394. if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
  395. ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
  396. {
  397. PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
  398. }
  399. pSpxConnFile->scf_LocalConnId = spxConnGetId();
  400. pSpxConnFile->scf_RemConnId = srcConnId;
  401. pSpxConnFile->scf_SendSeqNum = 0;
  402. pSpxConnFile->scf_RecvSeqNum = 0;
  403. pSpxConnFile->scf_RecdAckNum = 0;
  404. pSpxConnFile->scf_RetrySeqNum = 0;
  405. pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
  406. pSpxConnFile->scf_RecdAllocNum = allocNum;
  407. DBGPRINT(CONNECT, INFO,
  408. ("spxConnHandleConnReq: %lx CONN L.R %lx.%lx\n",
  409. pSpxConnFile,
  410. pSpxConnFile->scf_LocalConnId,
  411. pSpxConnFile->scf_RemConnId));
  412. pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
  413. pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
  414. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
  415. // Set max packet size in connection
  416. SPX_MAX_PKT_SIZE(pSpxConnFile, (fSpx2 && fNeg), fSpx2, pIpxSpxHdr->hdr_SrcNet);
  417. DBGPRINT(CONNECT, DBG,
  418. ("spxConnHandleConnReq: Accept connect req on %lx.%lx..%lx.%lx!\n",
  419. pSpxConnFile, pSpxConnFile->scf_LocalConnId,
  420. pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
  421. // Aborts must now deal with the lists. Need this as Accept has to
  422. // deal with it.
  423. // Put in non-inactive list. All processing now is equivalent to
  424. // that when a listen is completed on a connection.
  425. if ((!tdiListen) && (!NT_SUCCESS(spxConnRemoveFromList(
  426. &pSpxAddr->sa_InactiveConnList,
  427. pSpxConnFile))))
  428. {
  429. // Should never happen!
  430. KeBugCheck(0);
  431. }
  432. SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile);
  433. // Insert in the global connection tree on device.
  434. spxConnInsertIntoGlobalActiveList(
  435. pSpxConnFile);
  436. SPX_CONN_SETFLAG(pSpxConnFile,
  437. ((fNeg ? SPX_CONNFILE_NEG : 0) |
  438. (fSpx2 ? SPX_CONNFILE_SPX2: 0)));
  439. //
  440. // If this was a post-inactivated file, clear the disconnect flags
  441. //
  442. if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  443. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
  444. SPX_DISC_SETSTATE(pSpxConnFile, 0);
  445. }
  446. #if 0
  447. //
  448. // Make sure that this connection got a local disconnect if it was an SPXI
  449. // connection earlier, in response to a TDI_DISCONNECT_RELEASE.
  450. //
  451. CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX] == 0);
  452. #endif
  453. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
  454. SPX_LISTEN_SETSTATE(pSpxConnFile, (delayAccept ? SPX_LISTEN_RECDREQ : 0));
  455. if (!delayAccept)
  456. {
  457. spxConnAcceptCr(
  458. pSpxConnFile,
  459. pSpxAddr,
  460. lockHandleDev,
  461. lockHandle,
  462. lockHandleConn);
  463. }
  464. else
  465. {
  466. // Release the locks.
  467. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  468. CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
  469. CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
  470. // Complete the listen irp. Note reference is not removed. Done when
  471. // accept is posted.
  472. SpxCompleteRequest(pListenReq);
  473. }
  474. } else {
  475. ++SpxDevice->dev_Stat.NoListenFailures;
  476. }
  477. // Deref the address
  478. SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
  479. return;
  480. }
  481. VOID
  482. spxConnHandleSessPktFromClient(
  483. IN PIPXSPX_HDR pIpxSpxHdr,
  484. IN PIPX_LOCAL_TARGET pRemoteAddr,
  485. IN PSPX_CONN_FILE pSpxConnFile
  486. )
  487. /*++
  488. Routine Description:
  489. Packet received from the client side of the connection.
  490. Handles:
  491. Session Negotiate
  492. Sends Session Setup, when recd, handles SS Ack
  493. STATE MACHINE:
  494. RR
  495. / \
  496. / \ ReceivedAck(SPX1Connection)
  497. / \
  498. / \--------> ACTIVE
  499. / ^
  500. Send / |
  501. ACK / |
  502. / |
  503. / RecvNeg/NoNeg |
  504. / SendSS |
  505. SA--------->SS---------------+
  506. ^ | SSAckRecv
  507. | |
  508. +-----+
  509. RecvNeg
  510. RR - Received Connect Request
  511. SA - Sent CR Ack
  512. SS - Sent Session Setup
  513. We move from SA to SS when connection is not negotiatiable and we
  514. immediately send the SS, or when we receive negotiate packet and send the neg
  515. ack and the session setup.
  516. Note we could receive a negotiate packet when in SS, as our ack to the
  517. negotiate could have been dropped. We deal with this.
  518. Arguments:
  519. Return Value:
  520. --*/
  521. {
  522. PNDIS_PACKET pSnAckPkt, pSsPkt = NULL;
  523. PSPX_SEND_RESD pSendResd, pSsSendResd;
  524. USHORT srcConnId, destConnId, pktLen, seqNum = 0, negSize, ackNum, allocNum;
  525. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  526. BOOLEAN locksHeld = FALSE;
  527. GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
  528. GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
  529. GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
  530. GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
  531. GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
  532. // We keep and use the remote id in the net format. This maintains the
  533. // 0x0 and 0xFFFF to be as in the host format.
  534. srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
  535. // If spx2 we convert neg size field too
  536. if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
  537. {
  538. GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
  539. CTEAssert(negSize > 0);
  540. }
  541. // Grab all three locks
  542. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  543. CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
  544. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  545. locksHeld = TRUE;
  546. DBGPRINT(CONNECT, INFO,
  547. ("spxConnHandleSessPktFromClient: %lx\n", pSpxConnFile));
  548. // Check substate
  549. switch (SPX_LISTEN_STATE(pSpxConnFile))
  550. {
  551. case SPX_LISTEN_RECDREQ:
  552. // Do nothing.
  553. break;
  554. case SPX_LISTEN_SETUP:
  555. // Is this a setup ack? If so, yippee. Our ack to a negotiate packet
  556. // could have been dropped, and so we could also get a negotiate packet
  557. // in that case. If that happens, fall through.
  558. // Verify Ss Ack
  559. if (!SPX2_CONN(pSpxConnFile) ||
  560. (pktLen != MIN_IPXSPX2_HDRSIZE) ||
  561. ((pIpxSpxHdr->hdr_ConnCtrl &
  562. (SPX_CC_SYS | SPX_CC_SPX2)) !=
  563. (SPX_CC_SYS | SPX_CC_SPX2)) ||
  564. (pIpxSpxHdr->hdr_DataType != 0) ||
  565. (srcConnId == 0) ||
  566. (srcConnId == 0xFFFF) ||
  567. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  568. (destConnId == 0) ||
  569. (destConnId == 0xFFFF) ||
  570. (destConnId != pSpxConnFile->scf_LocalConnId) ||
  571. (seqNum != 0))
  572. {
  573. DBGPRINT(RECEIVE, DBG,
  574. ("SpxConnSysPacket: VerifySSACK Failed Checking SN %lx.%lx\n",
  575. srcConnId, destConnId));
  576. // Fall through to see if this is a neg packet
  577. if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG)))
  578. {
  579. break;
  580. }
  581. }
  582. else
  583. {
  584. DBGPRINT(CONNECT, DBG,
  585. ("spxConnHandleSessPktFromClient: Recd SSACK %lx\n",
  586. pSpxConnFile));
  587. spxConnCompleteConnect(
  588. pSpxConnFile,
  589. lockHandleDev,
  590. lockHandleAddr,
  591. lockHandleConn);
  592. locksHeld = FALSE;
  593. break;
  594. }
  595. case SPX_LISTEN_SENTACK:
  596. // We expect a negotiate packet.
  597. // We should have asked for SPX2/NEG to begin with.
  598. // Verify Sn
  599. if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
  600. (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
  601. ((pIpxSpxHdr->hdr_ConnCtrl &
  602. (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
  603. (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
  604. (pIpxSpxHdr->hdr_DataType != 0) ||
  605. (srcConnId == 0) ||
  606. (srcConnId == 0xFFFF) ||
  607. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  608. (destConnId == 0) ||
  609. (destConnId == 0xFFFF) ||
  610. (destConnId != pSpxConnFile->scf_LocalConnId) ||
  611. (seqNum != 0) ||
  612. ((negSize < SPX_NEG_MIN) ||
  613. (negSize > SPX_NEG_MAX)))
  614. {
  615. DBGPRINT(RECEIVE, ERR,
  616. ("SpxConnSysPacket: VerifySN Failed %lx.%lx\n",
  617. srcConnId, destConnId));
  618. break;
  619. }
  620. // Remember max packet size in connection.
  621. pSpxConnFile->scf_MaxPktSize = negSize;
  622. CTEAssert(negSize > 0);
  623. // Build sn ack, abort if we fail
  624. SpxPktBuildSnAck(
  625. pSpxConnFile,
  626. &pSnAckPkt,
  627. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY);
  628. if (pSnAckPkt == NULL)
  629. {
  630. spxConnAbortConnect(
  631. pSpxConnFile,
  632. STATUS_INSUFFICIENT_RESOURCES,
  633. lockHandleDev,
  634. lockHandleAddr,
  635. lockHandleConn);
  636. locksHeld = FALSE;
  637. break;
  638. }
  639. DBGPRINT(CONNECT, DBG,
  640. ("spxConnHandleSessPktFromClient: Sending SNACK %lx\n",
  641. pSpxConnFile));
  642. // Queue in the packet.
  643. SpxConnQueueSendPktTail(pSpxConnFile, pSnAckPkt);
  644. // The session packet should already be on queue.
  645. if (!spxConnGetPktByType(
  646. pSpxConnFile,
  647. SPX_TYPE_SS,
  648. FALSE,
  649. &pSsPkt))
  650. {
  651. KeBugCheck(0);
  652. }
  653. DBGPRINT(CONNECT, DBG,
  654. ("spxConnHandleSessPktFromClient: Sending SS %lx\n",
  655. pSpxConnFile));
  656. pSsSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
  657. // We need to resend the packet
  658. if ((pSsSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
  659. {
  660. // Try next time.
  661. pSsPkt = NULL;
  662. }
  663. else
  664. {
  665. // Set the size to the neg size indicated in connection.
  666. // This could be lower than the size the packet was build
  667. // with originally. But will never be higher.
  668. pSsSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
  669. spxConnSetNegSize(
  670. pSsPkt,
  671. pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
  672. }
  673. // If we are actually LISTEN_SETUP, then send the ss packet also.
  674. // We need to start the connect timer to resend the ss pkt.
  675. if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK)
  676. {
  677. if ((pSpxConnFile->scf_CTimerId =
  678. SpxTimerScheduleEvent(
  679. spxConnConnectTimer,
  680. PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
  681. pSpxConnFile)) == 0)
  682. {
  683. spxConnAbortConnect(
  684. pSpxConnFile,
  685. STATUS_INSUFFICIENT_RESOURCES,
  686. lockHandleDev,
  687. lockHandleAddr,
  688. lockHandleConn);
  689. locksHeld = FALSE;
  690. break;
  691. }
  692. // Reference connection for the timer
  693. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  694. SPX_LISTEN_SETSTATE(pSpxConnFile, SPX_LISTEN_SETUP);
  695. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  696. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
  697. }
  698. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  699. CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  700. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  701. locksHeld = FALSE;
  702. // Send ack packet
  703. pSendResd = (PSPX_SEND_RESD)(pSnAckPkt->ProtocolReserved);
  704. SPX_SENDPACKET(pSpxConnFile, pSnAckPkt, pSendResd);
  705. // If we have to send the session setup packet, send that too.
  706. if (pSsPkt != NULL)
  707. {
  708. pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
  709. SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
  710. }
  711. break;
  712. default:
  713. // Ignore
  714. DBGPRINT(RECEIVE, DBG,
  715. ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
  716. srcConnId, destConnId));
  717. break;
  718. }
  719. if (locksHeld)
  720. {
  721. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  722. CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  723. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  724. }
  725. return;
  726. }
  727. VOID
  728. spxConnHandleSessPktFromSrv(
  729. IN PIPXSPX_HDR pIpxSpxHdr,
  730. IN PIPX_LOCAL_TARGET pRemoteAddr,
  731. IN PSPX_CONN_FILE pSpxConnFile
  732. )
  733. /*++
  734. Routine Description:
  735. Packet received from the server side of the connection. This will both
  736. release the lock and dereference the connection as it sees fit.
  737. STATE MACHINE:
  738. SR--CTimerExpires-->IDLE
  739. /| \
  740. / | \ ReceivedAck(SPX1Connection)
  741. / | \
  742. / | \--------> ACTIVE
  743. (Neg) / | ^
  744. Send / |RecvAck |
  745. SN / |NoNeg |
  746. / | |
  747. / | |
  748. / v |
  749. SN--------->WS---------------+
  750. RecvSNAck RecvSS
  751. SR - Sent Connect request
  752. SN - Sent Session Negotiate
  753. WS - Waiting for session setup packet
  754. Arguments:
  755. Return Value:
  756. --*/
  757. {
  758. PSPX_SEND_RESD pSendResd;
  759. BOOLEAN fNeg, fSpx2;
  760. USHORT srcConnId, destConnId,
  761. pktLen, seqNum, negSize = 0, ackNum, allocNum;
  762. CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
  763. BOOLEAN cTimerCancelled = FALSE, fAbort = FALSE, locksHeld = FALSE;
  764. PNDIS_PACKET pSsAckPkt, pSnPkt, pPkt = NULL;
  765. // We should get a CR Ack, or if our substate is sent session neg
  766. // we should get a session neg ack, or if we are waiting for session
  767. // setup, we should get one of those.
  768. fSpx2 = (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2);
  769. fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
  770. GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
  771. GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
  772. GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
  773. GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
  774. GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
  775. // We keep and use the remote id in the net format. This maintains the
  776. // 0x0 and 0xFFFF to be as in the host format.
  777. srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
  778. // If spx2 we convert neg size field too
  779. if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
  780. {
  781. GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
  782. CTEAssert(negSize > 0);
  783. }
  784. // Grab all three locks
  785. CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
  786. CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
  787. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
  788. locksHeld = TRUE;
  789. DBGPRINT(CONNECT, INFO,
  790. ("spxConnHandleSessPktFromSrv: %lx\n", pSpxConnFile));
  791. // Check substate
  792. switch (SPX_CONNECT_STATE(pSpxConnFile))
  793. {
  794. case SPX_CONNECT_SENTREQ:
  795. // Check if this qualifies as the ack.
  796. // Verify CR Ack
  797. if ((pIpxSpxHdr->hdr_DataType != 0) ||
  798. (srcConnId == 0) ||
  799. (srcConnId == 0xFFFF) ||
  800. (destConnId == 0) ||
  801. (destConnId == 0xFFFF) ||
  802. (seqNum != 0) ||
  803. (ackNum != 0) ||
  804. ((pktLen != MIN_IPXSPX_HDRSIZE) &&
  805. ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
  806. (pktLen != MIN_IPXSPX2_HDRSIZE))) ||
  807. ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
  808. ((negSize < SPX_NEG_MIN) ||
  809. (negSize > SPX_NEG_MAX))))
  810. {
  811. DBGPRINT(CONNECT, ERR,
  812. ("spxConnHandleSessPktFromSrv: CRAck Invalid %lx %lx.%lx.%lx\n",
  813. pSpxConnFile,
  814. pktLen, negSize, pIpxSpxHdr->hdr_ConnCtrl));
  815. break;
  816. }
  817. // From current spx code base:
  818. // Do we need to send an ack to this ack? In case of SPX only?
  819. // What if this ack is dropped? We need to send an ack, if in future
  820. // we get CONNECT REQ Acks, until we reach active?
  821. // * If they want an ack schedule it. The normal case is for this not
  822. // * to happen, but some Novell mainframe front ends insist on having
  823. // * this. And technically, it is OK for them to do this.
  824. DBGPRINT(CONNECT, INFO,
  825. ("spxConnHandleSessPktFromSrv: Recd CRACK %lx\n", pSpxConnFile));
  826. // Grab the remote alloc num/conn id (in net format)
  827. pSpxConnFile->scf_SendSeqNum = 0;
  828. pSpxConnFile->scf_RecvSeqNum = 0;
  829. pSpxConnFile->scf_RecdAckNum = 0;
  830. pSpxConnFile->scf_RemConnId = srcConnId;
  831. pSpxConnFile->scf_RecdAllocNum = allocNum;
  832. // If we have been looking for network 0, which means the
  833. // packets were sent on all NIC IDs, update our local
  834. // target now that we have received a response.
  835. #if defined(_PNP_POWER)
  836. if (pSpxConnFile->scf_LocalTarget.NicHandle.NicId == (USHORT)ITERATIVE_NIC_ID) {
  837. #else
  838. if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
  839. #endif _PNP_POWER
  840. pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
  841. pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
  842. }
  843. DBGPRINT(CONNECT, INFO,
  844. ("spxConnHandleSessPktFromSrv: %lx CONN L.R %lx.%lx\n",
  845. pSpxConnFile,
  846. pSpxConnFile->scf_LocalConnId,
  847. pSpxConnFile->scf_RemConnId));
  848. if (!fSpx2 || !fNeg)
  849. {
  850. cTimerCancelled = SpxTimerCancelEvent(
  851. pSpxConnFile->scf_CTimerId, FALSE);
  852. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  853. if ((pSpxConnFile->scf_WTimerId =
  854. SpxTimerScheduleEvent(
  855. spxConnWatchdogTimer,
  856. PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
  857. pSpxConnFile)) == 0)
  858. {
  859. fAbort = TRUE;
  860. break;
  861. }
  862. // Reference transferred to watchdog timer.
  863. if (cTimerCancelled)
  864. {
  865. cTimerCancelled = FALSE;
  866. }
  867. else
  868. {
  869. // Reference connection for the timer
  870. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  871. }
  872. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  873. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  874. }
  875. // Set max packet size, assume not spx2 or !neg, so pass in FALSE
  876. SPX_MAX_PKT_SIZE(pSpxConnFile, FALSE, FALSE, pIpxSpxHdr->hdr_SrcNet);
  877. DBGPRINT(CONNECT, DBG,
  878. ("spxConnHandleSessPSrv: Accept connect req on %lx.%lx.%lx.%lx!\n",
  879. pSpxConnFile, pSpxConnFile->scf_LocalConnId,
  880. pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
  881. if (!fSpx2)
  882. {
  883. // Reset spx2 flags.
  884. SPX_CONN_RESETFLAG(pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
  885. // Complete connect request, this free the lock.
  886. // Cancels tdi timer too. Sets all necessary flags.
  887. spxConnCompleteConnect(
  888. pSpxConnFile,
  889. lockHandleDev,
  890. lockHandleAddr,
  891. lockHandleConn);
  892. locksHeld = FALSE;
  893. break;
  894. }
  895. if (!fNeg)
  896. {
  897. // Goto W_SETUP
  898. // Reset all connect related flags, also spx2/neg flags.
  899. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_NEG);
  900. SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
  901. break;
  902. }
  903. // Reset max packet size. SPX2 and NEG.
  904. SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, pIpxSpxHdr->hdr_SrcNet);
  905. CTEAssert(negSize > 0);
  906. CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
  907. pSpxConnFile->scf_MaxPktSize =
  908. MIN(negSize, pSpxConnFile->scf_MaxPktSize);
  909. pSpxConnFile->scf_MaxPktSize = (USHORT)
  910. MIN(pSpxConnFile->scf_MaxPktSize, PARAM(CONFIG_MAX_PACKET_SIZE));
  911. // For SPX2 with negotiation, we set up sneg packet and move to
  912. // SPX_CONNECT_NEG.
  913. SpxPktBuildSn(
  914. pSpxConnFile,
  915. &pSnPkt,
  916. SPX_SENDPKT_IPXOWNS);
  917. if (pSnPkt == NULL)
  918. {
  919. fAbort = TRUE;
  920. break;
  921. }
  922. // Queue in packet
  923. SpxConnQueueSendPktTail(pSpxConnFile, pSnPkt);
  924. DBGPRINT(CONNECT, DBG,
  925. ("spxConnHandleSessPktFromSrv: Sending SN %lx\n",
  926. pSpxConnFile));
  927. // Reset retry count for connect timer
  928. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
  929. // Change state.
  930. SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_NEG);
  931. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  932. CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  933. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  934. locksHeld = FALSE;
  935. // Send the packet
  936. pSendResd = (PSPX_SEND_RESD)(pSnPkt->ProtocolReserved);
  937. SPX_SENDPACKET(pSpxConnFile, pSnPkt, pSendResd);
  938. break;
  939. case SPX_CONNECT_NEG:
  940. // We expect a session neg ack.
  941. // We should have asked for SPX2/NEG to begin with.
  942. // Verify SN Ack
  943. if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
  944. (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
  945. (pktLen != MIN_IPXSPX2_HDRSIZE) ||
  946. ((pIpxSpxHdr->hdr_ConnCtrl &
  947. (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
  948. (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
  949. (pIpxSpxHdr->hdr_DataType != 0) ||
  950. (srcConnId == 0) ||
  951. (srcConnId == 0xFFFF) ||
  952. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  953. (destConnId == 0) ||
  954. (destConnId == 0xFFFF) ||
  955. (destConnId != pSpxConnFile->scf_LocalConnId) ||
  956. (seqNum != 0))
  957. {
  958. DBGPRINT(RECEIVE, ERR,
  959. ("SpxConnSysPacket: VerifySNACK Failed %lx.%lx\n",
  960. srcConnId, destConnId));
  961. break;
  962. }
  963. DBGPRINT(CONNECT, DBG,
  964. ("spxConnHandleSessPktFromSrv: Recd SNACK %lx %lx.%lx\n",
  965. pSpxConnFile, negSize, pSpxConnFile->scf_MaxPktSize));
  966. if (negSize > pSpxConnFile->scf_MaxPktSize)
  967. negSize = pSpxConnFile->scf_MaxPktSize;
  968. // Get the size to use
  969. if (negSize <= pSpxConnFile->scf_MaxPktSize)
  970. {
  971. pSpxConnFile->scf_MaxPktSize = negSize;
  972. if (!spxConnGetPktByType(
  973. pSpxConnFile,
  974. SPX_TYPE_SN,
  975. FALSE,
  976. &pPkt))
  977. {
  978. KeBugCheck(0);
  979. }
  980. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  981. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  982. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
  983. {
  984. // Set abort flag and reference conn for the pkt.
  985. pSendResd->sr_State |= SPX_SENDPKT_ABORT;
  986. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  987. }
  988. else
  989. {
  990. // Free the negotiate packet
  991. SpxPktSendRelease(pPkt);
  992. }
  993. CTEAssert(pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER);
  994. cTimerCancelled = SpxTimerCancelEvent(
  995. pSpxConnFile->scf_CTimerId, FALSE);
  996. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  997. // Start the watchdog timer, if fail, we abort.
  998. if ((pSpxConnFile->scf_WTimerId =
  999. SpxTimerScheduleEvent(
  1000. spxConnWatchdogTimer,
  1001. PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
  1002. pSpxConnFile)) == 0)
  1003. {
  1004. // Complete cr with error.
  1005. fAbort = TRUE;
  1006. break;
  1007. }
  1008. // Reference goes to watchdog timer.
  1009. if (cTimerCancelled)
  1010. {
  1011. cTimerCancelled = FALSE;
  1012. }
  1013. else
  1014. {
  1015. // Reference connection for the timer
  1016. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1017. }
  1018. // We move to the W_SETUP state.
  1019. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  1020. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  1021. SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
  1022. }
  1023. break;
  1024. case SPX_CONNECT_W_SETUP:
  1025. // Does this qualify as a session setup packet?
  1026. // Verify SS
  1027. if (!SPX2_CONN(pSpxConnFile) ||
  1028. ((pIpxSpxHdr->hdr_ConnCtrl &
  1029. (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) !=
  1030. (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) ||
  1031. (pIpxSpxHdr->hdr_DataType != 0) ||
  1032. (srcConnId == 0) ||
  1033. (srcConnId == 0xFFFF) ||
  1034. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  1035. (destConnId == 0) ||
  1036. (destConnId == 0xFFFF) ||
  1037. (destConnId != pSpxConnFile->scf_LocalConnId) ||
  1038. (seqNum != 0) ||
  1039. ((negSize < SPX_NEG_MIN) ||
  1040. (negSize > SPX_NEG_MAX)))
  1041. {
  1042. DBGPRINT(RECEIVE, ERR,
  1043. ("SpxConnSysPacket: VerifySS Failed %lx.%lx, %lx %lx.%lx\n",
  1044. srcConnId, destConnId, negSize,
  1045. pIpxSpxHdr->hdr_ConnCtrl,
  1046. (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)));
  1047. break;
  1048. }
  1049. DBGPRINT(CONNECT, DBG,
  1050. ("spxConnHandleSessPktFromSrv: Recd SS %lx\n", pSpxConnFile));
  1051. // Copy remote address over into connection (socket could change)
  1052. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
  1053. // Remember max packet size in connection.
  1054. pSpxConnFile->scf_MaxPktSize = negSize;
  1055. // Build ss ack, abort if we fail
  1056. SpxPktBuildSsAck(
  1057. pSpxConnFile,
  1058. &pSsAckPkt,
  1059. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT);
  1060. if (pSsAckPkt == NULL)
  1061. {
  1062. fAbort = TRUE;
  1063. break;
  1064. }
  1065. DBGPRINT(CONNECT, DBG,
  1066. ("spxConnHandleSessPktFromSrv: Sending SSACK %lx\n",
  1067. pSpxConnFile));
  1068. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  1069. // We dont queue in the pkt as its already marked as abort.
  1070. // Queue in the packet.
  1071. // SpxConnQueueSendPktTail(pSpxConnFile, pSsAckPkt);
  1072. // Complete connect, this releases lock.
  1073. spxConnCompleteConnect(
  1074. pSpxConnFile,
  1075. lockHandleDev,
  1076. lockHandleAddr,
  1077. lockHandleConn);
  1078. locksHeld = FALSE;
  1079. // Send ack packet
  1080. pSendResd = (PSPX_SEND_RESD)(pSsAckPkt->ProtocolReserved);
  1081. SPX_SENDPACKET(pSpxConnFile, pSsAckPkt, pSendResd);
  1082. break;
  1083. default:
  1084. // Ignore
  1085. DBGPRINT(RECEIVE, DBG,
  1086. ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
  1087. srcConnId, destConnId));
  1088. break;
  1089. }
  1090. if (fAbort)
  1091. {
  1092. spxConnAbortConnect(
  1093. pSpxConnFile,
  1094. STATUS_INSUFFICIENT_RESOURCES,
  1095. lockHandleDev,
  1096. lockHandleAddr,
  1097. lockHandleConn);
  1098. locksHeld = FALSE;
  1099. }
  1100. if (locksHeld)
  1101. {
  1102. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
  1103. CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
  1104. CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
  1105. }
  1106. if (cTimerCancelled)
  1107. {
  1108. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1109. }
  1110. return;
  1111. }
  1112. VOID
  1113. spxConnAbortConnect(
  1114. IN PSPX_CONN_FILE pSpxConnFile,
  1115. IN NTSTATUS Status,
  1116. IN CTELockHandle LockHandleDev,
  1117. IN CTELockHandle LockHandleAddr,
  1118. IN CTELockHandle LockHandleConn
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. This routine abort a connection (both client and server side) in the middle
  1123. of a connection establishment.
  1124. !!! Called with connection lock held, releases lock before return !!!
  1125. Arguments:
  1126. Return Value:
  1127. --*/
  1128. {
  1129. PSPX_SEND_RESD pSendResd;
  1130. PNDIS_PACKET pPkt;
  1131. PREQUEST pRequest = NULL;
  1132. int numDerefs = 0;
  1133. DBGPRINT(CONNECT, DBG,
  1134. ("spxConnAbortConnect: %lx\n", pSpxConnFile));
  1135. #if DBG
  1136. if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
  1137. {
  1138. KeBugCheck(0);
  1139. }
  1140. #endif
  1141. if (Status == STATUS_INSUFFICIENT_RESOURCES) { // others should be counted elsewhere
  1142. ++SpxDevice->dev_Stat.LocalResourceFailures;
  1143. }
  1144. // Free up all the packets
  1145. while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
  1146. {
  1147. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1148. pSendResd, NDIS_PACKET, ProtocolReserved);
  1149. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  1150. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
  1151. {
  1152. // Free the packet
  1153. SpxPktSendRelease(pPkt);
  1154. }
  1155. else
  1156. {
  1157. // Set abort flag and reference conn for the pkt.
  1158. pSendResd->sr_State |= SPX_SENDPKT_ABORT;
  1159. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  1160. }
  1161. }
  1162. // Cancel all timers
  1163. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
  1164. {
  1165. if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
  1166. {
  1167. numDerefs++;
  1168. }
  1169. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
  1170. }
  1171. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
  1172. {
  1173. if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
  1174. {
  1175. numDerefs++;
  1176. }
  1177. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  1178. }
  1179. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
  1180. {
  1181. if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
  1182. {
  1183. numDerefs++;
  1184. }
  1185. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  1186. }
  1187. // We could be called from disconnect for an accept in which case there
  1188. // will be no queued request. But we need to remove the reference if there
  1189. // is no request (an accept/listen irp) and listen state is on.
  1190. CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
  1191. if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
  1192. {
  1193. pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
  1194. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  1195. REQUEST_STATUS(pRequest) = Status;
  1196. REQUEST_INFORMATION(pRequest) = 0;
  1197. // Save req in conn for deref to complete.
  1198. pSpxConnFile->scf_ConnectReq = pRequest;
  1199. numDerefs++;
  1200. }
  1201. else if (SPX_CONN_LISTENING(pSpxConnFile))
  1202. {
  1203. numDerefs++;
  1204. }
  1205. // Bug #20999
  1206. // Race condition was an abort came in from timer, but the connect state
  1207. // was left unchanged. Due to an extra ref on the connection from the
  1208. // aborted cr, the state remained so, and then the cr ack came in, and
  1209. // a session neg was built and queued on the connection. Although it should
  1210. // not have been. And we hit the assert in deref where the connection is
  1211. // being reinitialized. Since this can be called for both listening and
  1212. // connecting connections, do the below.
  1213. SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
  1214. if (SPX_CONN_CONNECTING(pSpxConnFile))
  1215. {
  1216. SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
  1217. }
  1218. CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
  1219. CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
  1220. CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
  1221. while (numDerefs-- > 0)
  1222. {
  1223. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1224. }
  1225. return;
  1226. }
  1227. VOID
  1228. spxConnCompleteConnect(
  1229. IN PSPX_CONN_FILE pSpxConnFile,
  1230. IN CTELockHandle LockHandleDev,
  1231. IN CTELockHandle LockHandleAddr,
  1232. IN CTELockHandle LockHandleConn
  1233. )
  1234. /*++
  1235. Routine Description:
  1236. This routine completes a connection (both client and server side)
  1237. !!! Called with connection lock held, releases lock before return !!!
  1238. Arguments:
  1239. Return Value:
  1240. --*/
  1241. {
  1242. PREQUEST pRequest;
  1243. PSPX_SEND_RESD pSendResd;
  1244. PNDIS_PACKET pPkt;
  1245. int numDerefs = 0;
  1246. DBGPRINT(CONNECT, INFO,
  1247. ("spxConnCompleteConnect: %lx\n", pSpxConnFile));
  1248. #if DBG
  1249. if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
  1250. {
  1251. DBGBRK(FATAL);
  1252. }
  1253. #endif
  1254. // Free up all the packets
  1255. while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
  1256. {
  1257. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1258. pSendResd, NDIS_PACKET, ProtocolReserved);
  1259. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  1260. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
  1261. {
  1262. // Free the packet
  1263. SpxPktSendRelease(pPkt);
  1264. }
  1265. else
  1266. {
  1267. // Set abort flag and reference conn for the pkt.
  1268. pSendResd->sr_State |= SPX_SENDPKT_ABORT;
  1269. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  1270. }
  1271. }
  1272. // Cancel tdi connect timer if we are connecting.
  1273. switch (SPX_MAIN_STATE(pSpxConnFile))
  1274. {
  1275. case SPX_CONNFILE_CONNECTING:
  1276. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
  1277. {
  1278. if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
  1279. {
  1280. numDerefs++;
  1281. }
  1282. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
  1283. }
  1284. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
  1285. {
  1286. if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
  1287. {
  1288. numDerefs++;
  1289. }
  1290. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  1291. }
  1292. if (pSpxConnFile->scf_CRetryCount == (LONG)(PARAM(CONFIG_CONNECTION_COUNT))) {
  1293. ++SpxDevice->dev_Stat.ConnectionsAfterNoRetry;
  1294. } else {
  1295. ++SpxDevice->dev_Stat.ConnectionsAfterRetry;
  1296. }
  1297. // Reset all connect related flags
  1298. SPX_MAIN_SETSTATE(pSpxConnFile, 0);
  1299. SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
  1300. break;
  1301. case SPX_CONNFILE_LISTENING:
  1302. if (pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER)
  1303. {
  1304. if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
  1305. {
  1306. numDerefs++;
  1307. }
  1308. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  1309. }
  1310. SPX_MAIN_SETSTATE(pSpxConnFile, 0);
  1311. SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
  1312. break;
  1313. default:
  1314. KeBugCheck(0);
  1315. }
  1316. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_ACTIVE);
  1317. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  1318. SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_IDLE);
  1319. ++SpxDevice->dev_Stat.OpenConnections;
  1320. // Initialize timer values
  1321. pSpxConnFile->scf_BaseT1 =
  1322. pSpxConnFile->scf_AveT1 = PARAM(CONFIG_INITIAL_RETRANSMIT_TIMEOUT);
  1323. pSpxConnFile->scf_DevT1 = 0;
  1324. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  1325. pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
  1326. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  1327. REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
  1328. REQUEST_INFORMATION(pRequest) = 0;
  1329. // When we complete the request, we essentially transfer the reference
  1330. // to the fact that the connection is active. This will be taken away
  1331. // when a Disconnect happens on the connection and we transition from
  1332. // ACTIVE to DISCONN.
  1333. // numDerefs++;
  1334. CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
  1335. CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
  1336. CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
  1337. // Complete request
  1338. SpxCompleteRequest(pRequest);
  1339. while (numDerefs-- > 0)
  1340. {
  1341. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1342. }
  1343. return;
  1344. }
  1345. BOOLEAN
  1346. spxConnAcceptCr(
  1347. IN PSPX_CONN_FILE pSpxConnFile,
  1348. IN PSPX_ADDR pSpxAddr,
  1349. IN CTELockHandle LockHandleDev,
  1350. IN CTELockHandle LockHandleAddr,
  1351. IN CTELockHandle LockHandleConn
  1352. )
  1353. {
  1354. PNDIS_PACKET pSsPkt, pCrAckPkt;
  1355. PSPX_SEND_RESD pSendResd;
  1356. BOOLEAN fNeg = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG);
  1357. BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
  1358. DBGPRINT(CONNECT, DBG,
  1359. ("spxConnAcceptCr: %lx.%d.%d\n",
  1360. pSpxConnFile, fSpx2, fNeg));
  1361. // Build and queue in packet.
  1362. SpxPktBuildCrAck(
  1363. pSpxConnFile,
  1364. pSpxAddr,
  1365. &pCrAckPkt,
  1366. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
  1367. fNeg,
  1368. fSpx2);
  1369. if ((pCrAckPkt != NULL) &&
  1370. (pSpxConnFile->scf_LocalConnId != 0))
  1371. {
  1372. // Queue in the packet.
  1373. SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
  1374. }
  1375. else
  1376. {
  1377. goto AbortConnect;
  1378. }
  1379. // Start the timer
  1380. if ((pSpxConnFile->scf_WTimerId =
  1381. SpxTimerScheduleEvent(
  1382. spxConnWatchdogTimer,
  1383. PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
  1384. pSpxConnFile)) != 0)
  1385. {
  1386. // Reference connection for the timer
  1387. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1388. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
  1389. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  1390. }
  1391. else
  1392. {
  1393. goto AbortConnect;
  1394. }
  1395. // We start the connect timer for retrying ss which we send out now
  1396. // if we are not negotiating.
  1397. if (fSpx2)
  1398. {
  1399. // Build the session setup packet also for spx2.
  1400. SpxPktBuildSs(
  1401. pSpxConnFile,
  1402. &pSsPkt,
  1403. (USHORT)(fNeg ? 0 : SPX_SENDPKT_IPXOWNS));
  1404. if (pSsPkt != NULL)
  1405. {
  1406. SpxConnQueueSendPktTail(pSpxConnFile, pSsPkt);
  1407. }
  1408. else
  1409. {
  1410. goto AbortConnect;
  1411. }
  1412. if (!fNeg)
  1413. {
  1414. if ((pSpxConnFile->scf_CTimerId =
  1415. SpxTimerScheduleEvent(
  1416. spxConnConnectTimer,
  1417. PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
  1418. pSpxConnFile)) != 0)
  1419. {
  1420. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
  1421. pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
  1422. // Reference connection for the timer
  1423. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1424. }
  1425. else
  1426. {
  1427. goto AbortConnect;
  1428. }
  1429. }
  1430. }
  1431. CTEAssert((fNeg && fSpx2) || (!fSpx2 && !fNeg));
  1432. // For a SPX connection, we immediately become active. This happens
  1433. // in the completeConnect routine. !!Dont change it here!!
  1434. if (!fSpx2)
  1435. {
  1436. spxConnCompleteConnect(
  1437. pSpxConnFile,
  1438. LockHandleDev,
  1439. LockHandleAddr,
  1440. LockHandleConn);
  1441. }
  1442. else
  1443. {
  1444. SPX_LISTEN_SETSTATE(
  1445. pSpxConnFile, (fNeg ? SPX_LISTEN_SENTACK : SPX_LISTEN_SETUP));
  1446. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1447. CTEFreeLock (&pSpxAddr->sa_Lock, LockHandleAddr);
  1448. CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
  1449. }
  1450. // Send the CR Ack packet!
  1451. pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
  1452. SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
  1453. if (fSpx2 && !fNeg)
  1454. {
  1455. pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
  1456. SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
  1457. }
  1458. return(TRUE);
  1459. AbortConnect:
  1460. spxConnAbortConnect(
  1461. pSpxConnFile,
  1462. STATUS_INSUFFICIENT_RESOURCES,
  1463. LockHandleDev,
  1464. LockHandleAddr,
  1465. LockHandleConn);
  1466. return (FALSE);
  1467. }
  1468. BOOLEAN
  1469. SpxConnPacketize(
  1470. IN PSPX_CONN_FILE pSpxConnFile,
  1471. IN BOOLEAN fNormalState,
  1472. IN CTELockHandle LockHandleConn
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. The caller needs to set the state to packetize before calling this
  1477. routine. This can be called when SEND state is RENEG also.
  1478. Arguments:
  1479. pSpxConnFile - Pointer to a transport address file object.
  1480. fNormalState - If true, it will assume it can release lock to send,
  1481. else, it just builds pkts without releasing lock and
  1482. releases lock at end. Used after reneg changes size.
  1483. Return Value:
  1484. --*/
  1485. {
  1486. PLIST_ENTRY p;
  1487. PNDIS_PACKET pPkt;
  1488. PSPX_SEND_RESD pSendResd;
  1489. USHORT windowSize;
  1490. ULONG dataLen;
  1491. USHORT sendFlags;
  1492. int numDerefs = 0;
  1493. BOOLEAN fFirstPass = TRUE, fSuccess = TRUE;
  1494. PREQUEST pRequest;
  1495. #if DBG
  1496. if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
  1497. fNormalState)
  1498. {
  1499. DBGBRK(FATAL);
  1500. KeBugCheck(0);
  1501. }
  1502. #endif
  1503. // Build all of the packets. The firsttime flag is used so
  1504. // that if we get a 0 byte send, we will send it. The firsttime
  1505. // flag will be set and we will build the packet and send it.
  1506. //
  1507. // FOR SPX1, we cannot trust the remote window size. So we only send
  1508. // stuff if window size is greater than 0 *AND* we do not have any pending
  1509. // sends. Dont get in here if we are ABORT. Dont want to be handling any
  1510. // more requests.
  1511. while((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ABORT) &&
  1512. ((pRequest = pSpxConnFile->scf_ReqPkt) != NULL) &&
  1513. ((pSpxConnFile->scf_ReqPktSize > 0) || fFirstPass))
  1514. {
  1515. fFirstPass = FALSE;
  1516. windowSize = pSpxConnFile->scf_RecdAllocNum -
  1517. pSpxConnFile->scf_SendSeqNum + 1;
  1518. DBGPRINT(SEND, DBG,
  1519. ("SpxConnPacketize: WINDOW %lx for %lx\n",
  1520. windowSize, pSpxConnFile));
  1521. DBGPRINT(SEND, DBG,
  1522. ("REMALLOC %lx SENDSEQ %lx\n",
  1523. pSpxConnFile->scf_RecdAllocNum,
  1524. pSpxConnFile->scf_SendSeqNum));
  1525. CTEAssert(windowSize >= 0);
  1526. // Disconnect/Orderly release is not subject to window closure.
  1527. if ((pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA) &&
  1528. ((windowSize == 0) ||
  1529. (!SPX2_CONN(pSpxConnFile) &&
  1530. (pSpxConnFile->scf_SendSeqListHead != NULL))))
  1531. {
  1532. break;
  1533. }
  1534. if (pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA)
  1535. {
  1536. CTEAssert(pRequest == pSpxConnFile->scf_ReqPkt);
  1537. // Get data length
  1538. dataLen = (ULONG)MIN(pSpxConnFile->scf_ReqPktSize,
  1539. (pSpxConnFile->scf_MaxPktSize -
  1540. ((SPX2_CONN(pSpxConnFile) ?
  1541. MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE))));
  1542. DBGPRINT(SEND, DBG,
  1543. ("SpxConnPacketize: %lx Sending %lx Size %lx Req %lx.%lx\n",
  1544. pSpxConnFile,
  1545. pSpxConnFile->scf_SendSeqNum,
  1546. dataLen,
  1547. pSpxConnFile->scf_ReqPkt,
  1548. pSpxConnFile->scf_ReqPktSize));
  1549. // Build data packet. Handles 0-length for data. Puts in seq num in
  1550. // send resd section of packet also.
  1551. sendFlags =
  1552. (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) |
  1553. SPX_SENDPKT_REQ |
  1554. SPX_SENDPKT_SEQ |
  1555. ((!SPX2_CONN(pSpxConnFile) || (windowSize == 1)) ?
  1556. SPX_SENDPKT_ACKREQ : 0));
  1557. if (dataLen == pSpxConnFile->scf_ReqPktSize)
  1558. {
  1559. // Last packet of send, ask for a ack.
  1560. sendFlags |= (SPX_SENDPKT_LASTPKT | SPX_SENDPKT_ACKREQ);
  1561. if ((pSpxConnFile->scf_ReqPktFlags & TDI_SEND_PARTIAL) == 0)
  1562. sendFlags |= SPX_SENDPKT_EOM;
  1563. }
  1564. SpxPktBuildData(
  1565. pSpxConnFile,
  1566. &pPkt,
  1567. sendFlags,
  1568. (USHORT)dataLen);
  1569. }
  1570. else
  1571. {
  1572. dataLen = 0;
  1573. DBGPRINT(SEND, DBG,
  1574. ("Building DISC packet on %lx ReqPktSize %lx\n",
  1575. pSpxConnFile, pSpxConnFile->scf_ReqPktSize));
  1576. // Build informed disc/orderly rel packet, associate with request
  1577. SpxPktBuildDisc(
  1578. pSpxConnFile,
  1579. pRequest,
  1580. &pPkt,
  1581. (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) | SPX_SENDPKT_REQ |
  1582. SPX_SENDPKT_SEQ | SPX_SENDPKT_LASTPKT),
  1583. (UCHAR)((pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL) ?
  1584. SPX2_DT_ORDREL : SPX2_DT_IDISC));
  1585. }
  1586. if (pPkt != NULL)
  1587. {
  1588. // If we were waiting to send an ack, we don't have to as we are
  1589. // piggybacking it now. Cancel ack timer, get out.
  1590. if (fNormalState && SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
  1591. {
  1592. DBGPRINT(SEND, DBG,
  1593. ("SpxConnPacketize: Piggyback happening for %lx.%lx\n",
  1594. pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
  1595. // We are sending data, allow piggybacks to happen.
  1596. SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
  1597. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
  1598. if (SpxTimerCancelEvent(pSpxConnFile->scf_ATimerId, FALSE))
  1599. {
  1600. numDerefs++;
  1601. }
  1602. }
  1603. if (pSpxConnFile->scf_ReqPktType != SPX_REQ_DATA)
  1604. {
  1605. // For a disconnect set the state
  1606. if (pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL)
  1607. {
  1608. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
  1609. {
  1610. SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
  1611. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
  1612. numDerefs++;
  1613. }
  1614. else if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_ORDREL)
  1615. {
  1616. CTEAssert((SPX_MAIN_STATE(pSpxConnFile) ==
  1617. SPX_CONNFILE_ACTIVE) ||
  1618. (SPX_MAIN_STATE(pSpxConnFile) ==
  1619. SPX_CONNFILE_DISCONN));
  1620. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
  1621. }
  1622. else
  1623. {
  1624. CTEAssert(
  1625. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL));
  1626. }
  1627. }
  1628. else
  1629. {
  1630. CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
  1631. CTEAssert(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC);
  1632. // Note we have send the idisc here.
  1633. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_IDISC);
  1634. }
  1635. }
  1636. }
  1637. else
  1638. {
  1639. fSuccess = FALSE;
  1640. break;
  1641. }
  1642. // Queue in packet, reference request for the packet
  1643. SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt);
  1644. REQUEST_INFORMATION(pRequest)++;
  1645. pSpxConnFile->scf_ReqPktSize -= dataLen;
  1646. pSpxConnFile->scf_ReqPktOffset += dataLen;
  1647. DBGPRINT(SEND, INFO,
  1648. ("SpxConnPacketize: Req %lx Size after pkt %lx.%lx\n",
  1649. pSpxConnFile->scf_ReqPkt, pSpxConnFile->scf_ReqPktSize,
  1650. dataLen));
  1651. // Even if window size if zero, setup next request is current one
  1652. // is done. We are here only after we have packetized this send req.
  1653. if (pSpxConnFile->scf_ReqPktSize == 0)
  1654. {
  1655. // This request has been fully packetized. Either go on to
  1656. // next request or we are done packetizing.
  1657. p = REQUEST_LINKAGE(pRequest);
  1658. if (p->Flink == &pSpxConnFile->scf_ReqLinkage)
  1659. {
  1660. DBGPRINT(SEND, INFO,
  1661. ("SpxConnPacketize: Req %lx done, no more\n",
  1662. pRequest));
  1663. pSpxConnFile->scf_ReqPkt = NULL;
  1664. pSpxConnFile->scf_ReqPktSize = 0;
  1665. pSpxConnFile->scf_ReqPktOffset = 0;
  1666. pRequest = NULL;
  1667. }
  1668. else
  1669. {
  1670. pRequest = LIST_ENTRY_TO_REQUEST(p->Flink);
  1671. if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
  1672. {
  1673. PTDI_REQUEST_KERNEL_SEND pParam;
  1674. pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
  1675. DBGPRINT(SEND, DBG,
  1676. ("SpxConnPacketize: Req done, setting next %lx.%lx\n",
  1677. pRequest, pParam->SendLength));
  1678. DBGPRINT(SEND, INFO,
  1679. ("-%lx-\n",
  1680. pRequest));
  1681. // Set parameters in connection for another go.
  1682. pSpxConnFile->scf_ReqPkt = pRequest;
  1683. pSpxConnFile->scf_ReqPktOffset = 0;
  1684. pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
  1685. pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
  1686. if ((pSpxConnFile->scf_ReqPktSize = pParam->SendLength) == 0)
  1687. {
  1688. // Another zero length send.
  1689. fFirstPass = TRUE;
  1690. }
  1691. }
  1692. else
  1693. {
  1694. PTDI_REQUEST_KERNEL_DISCONNECT pParam;
  1695. pParam =
  1696. (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
  1697. pSpxConnFile->scf_ReqPkt = pRequest;
  1698. pSpxConnFile->scf_ReqPktOffset = 0;
  1699. pSpxConnFile->scf_ReqPktSize = 0;
  1700. fFirstPass = TRUE;
  1701. pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
  1702. if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
  1703. {
  1704. pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
  1705. }
  1706. }
  1707. }
  1708. }
  1709. if (fNormalState)
  1710. {
  1711. // Send the packet if we are not at the reneg state
  1712. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1713. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  1714. ++SpxDevice->dev_Stat.DataFramesSent;
  1715. ExInterlockedAddLargeStatistic(
  1716. &SpxDevice->dev_Stat.DataFrameBytesSent,
  1717. dataLen);
  1718. SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
  1719. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  1720. }
  1721. // Check if retry timer needs to be started.
  1722. if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)))
  1723. {
  1724. if ((pSpxConnFile->scf_RTimerId =
  1725. SpxTimerScheduleEvent(
  1726. spxConnRetryTimer,
  1727. pSpxConnFile->scf_BaseT1,
  1728. pSpxConnFile)) != 0)
  1729. {
  1730. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
  1731. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  1732. // Reference connection for the timer
  1733. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1734. }
  1735. else
  1736. {
  1737. DBGPRINT(SEND, ERR,
  1738. ("SpxConnPacketize: Failed to start retry timer\n"));
  1739. fSuccess = FALSE;
  1740. break;
  1741. }
  1742. }
  1743. }
  1744. // Dont overwrite an error state.
  1745. if (((fNormalState) &&
  1746. (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)) ||
  1747. ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3) &&
  1748. (pSpxConnFile->scf_SendSeqListHead == NULL)))
  1749. {
  1750. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
  1751. {
  1752. DBGPRINT(SEND, ERR,
  1753. ("COULD NOT PACKETIZE AFTER RENEG %lx\n", pSpxConnFile));
  1754. SpxConnFileTransferReference(
  1755. pSpxConnFile,
  1756. CFREF_ERRORSTATE,
  1757. CFREF_VERIFY);
  1758. numDerefs++;
  1759. }
  1760. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  1761. }
  1762. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1763. while (numDerefs-- > 0)
  1764. {
  1765. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1766. }
  1767. return(fSuccess);
  1768. }
  1769. VOID
  1770. SpxConnQueueRecv(
  1771. IN PSPX_CONN_FILE pSpxConnFile,
  1772. IN PREQUEST pRequest
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. Arguments:
  1777. pSpxConnFile - Pointer to a transport address file object.
  1778. Return Value:
  1779. --*/
  1780. {
  1781. PTDI_REQUEST_KERNEL_RECEIVE pParam;
  1782. NTSTATUS status = STATUS_PENDING;
  1783. if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
  1784. {
  1785. pParam = (PTDI_REQUEST_KERNEL_RECEIVE)REQUEST_PARAMETERS(pRequest);
  1786. pSpxConnFile->scf_CurRecvReq = pRequest;
  1787. pSpxConnFile->scf_CurRecvOffset = 0;
  1788. pSpxConnFile->scf_CurRecvSize = pParam->ReceiveLength;
  1789. }
  1790. DBGPRINT(RECEIVE, DBG,
  1791. ("spxConnQueueRecv: %lx.%lx\n", pRequest, pParam->ReceiveLength));
  1792. // Reference connection for this recv.
  1793. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1794. InsertTailList(
  1795. &pSpxConnFile->scf_RecvLinkage,
  1796. REQUEST_LINKAGE(pRequest));
  1797. // RECV irps have no creation references.
  1798. REQUEST_INFORMATION(pRequest) = 0;
  1799. REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
  1800. // State to receive_posted if we are idle.
  1801. if (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE)
  1802. {
  1803. SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_POSTED);
  1804. }
  1805. return;
  1806. }
  1807. VOID
  1808. spxConnCompletePended(
  1809. IN PSPX_CONN_FILE pSpxConnFile
  1810. )
  1811. {
  1812. CTELockHandle lockHandleInter;
  1813. LIST_ENTRY ReqList, *p;
  1814. PREQUEST pRequest;
  1815. InitializeListHead(&ReqList);
  1816. DBGPRINT(RECEIVE, DBG,
  1817. ("spxConnCompletePended: PENDING RECV REQUESTS IN DONE LIST! %lx\n",
  1818. pSpxConnFile));
  1819. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  1820. p = pSpxConnFile->scf_RecvDoneLinkage.Flink;
  1821. while (p != &pSpxConnFile->scf_RecvDoneLinkage)
  1822. {
  1823. pRequest = LIST_ENTRY_TO_REQUEST(p);
  1824. p = p->Flink;
  1825. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  1826. InsertTailList(
  1827. &ReqList,
  1828. REQUEST_LINKAGE(pRequest));
  1829. }
  1830. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  1831. while (!IsListEmpty(&ReqList))
  1832. {
  1833. p = RemoveHeadList(&ReqList);
  1834. pRequest = LIST_ENTRY_TO_REQUEST(p);
  1835. DBGPRINT(TDI, DBG,
  1836. ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
  1837. pRequest, REQUEST_STATUS(pRequest),
  1838. REQUEST_INFORMATION(pRequest)));
  1839. #if DBG
  1840. if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_RECEIVE)
  1841. {
  1842. if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
  1843. (REQUEST_INFORMATION(pRequest) == 0))
  1844. {
  1845. DBGPRINT(TDI, DBG,
  1846. ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
  1847. pRequest, REQUEST_STATUS(pRequest),
  1848. REQUEST_INFORMATION(pRequest)));
  1849. }
  1850. }
  1851. #endif
  1852. SpxCompleteRequest(pRequest);
  1853. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1854. }
  1855. return;
  1856. }
  1857. VOID
  1858. SpxConnQWaitAck(
  1859. IN PSPX_CONN_FILE pSpxConnFile
  1860. )
  1861. /*++
  1862. Routine Description:
  1863. Arguments:
  1864. pSpxConnFile - Pointer to a transport address file object.
  1865. Return Value:
  1866. --*/
  1867. {
  1868. // If we are not already in ack queue, queue ourselves in starting
  1869. // ack timer.
  1870. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
  1871. {
  1872. // First start ack timer.
  1873. if ((pSpxConnFile->scf_ATimerId =
  1874. SpxTimerScheduleEvent(
  1875. spxConnAckTimer,
  1876. 100,
  1877. pSpxConnFile)) != 0)
  1878. {
  1879. // Reference connection for timer
  1880. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  1881. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
  1882. ++SpxDevice->dev_Stat.PiggybackAckQueued;
  1883. }
  1884. }
  1885. return;
  1886. }
  1887. VOID
  1888. SpxConnSendAck(
  1889. IN PSPX_CONN_FILE pSpxConnFile,
  1890. IN CTELockHandle LockHandleConn
  1891. )
  1892. /*++
  1893. Routine Description:
  1894. Arguments:
  1895. pSpxConnFile - Pointer to a transport address file object.
  1896. Return Value:
  1897. --*/
  1898. {
  1899. PSPX_SEND_RESD pSendResd;
  1900. PNDIS_PACKET pPkt = NULL;
  1901. DBGPRINT(SEND, DBG,
  1902. ("spxConnSendAck: ACKING on %lx.%lx\n",
  1903. pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
  1904. // Build an ack packet, queue it in non-sequenced queue. Only if we are
  1905. // active.
  1906. if (SPX_CONN_ACTIVE(pSpxConnFile))
  1907. {
  1908. SpxPktBuildAck(
  1909. pSpxConnFile,
  1910. &pPkt,
  1911. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
  1912. FALSE,
  1913. 0);
  1914. if (pPkt != NULL)
  1915. {
  1916. SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
  1917. }
  1918. else
  1919. {
  1920. // Log error
  1921. DBGPRINT(SEND, ERR,
  1922. ("SpxConnSendAck: Could not allocate!\n"));
  1923. }
  1924. }
  1925. #if DBG
  1926. else
  1927. {
  1928. DBGPRINT(SEND, DBG,
  1929. ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
  1930. }
  1931. #endif
  1932. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1933. // Send it.
  1934. if (pPkt != NULL)
  1935. {
  1936. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  1937. // Send the packet
  1938. SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
  1939. }
  1940. return;
  1941. }
  1942. VOID
  1943. SpxConnSendNack(
  1944. IN PSPX_CONN_FILE pSpxConnFile,
  1945. IN USHORT NumToSend,
  1946. IN CTELockHandle LockHandleConn
  1947. )
  1948. /*++
  1949. Routine Description:
  1950. Arguments:
  1951. pSpxConnFile - Pointer to a transport address file object.
  1952. Return Value:
  1953. --*/
  1954. {
  1955. PSPX_SEND_RESD pSendResd;
  1956. PNDIS_PACKET pPkt = NULL;
  1957. DBGPRINT(SEND, DBG,
  1958. ("spxConnSendNack: NACKING on %lx.%lx\n",
  1959. pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
  1960. // Build an nack packet, queue it in non-sequenced queue. Only if we are
  1961. // active.
  1962. if (SPX_CONN_ACTIVE(pSpxConnFile))
  1963. {
  1964. SpxPktBuildAck(
  1965. pSpxConnFile,
  1966. &pPkt,
  1967. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
  1968. TRUE,
  1969. NumToSend);
  1970. if (pPkt != NULL)
  1971. {
  1972. SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
  1973. }
  1974. else
  1975. {
  1976. // Log error
  1977. DBGPRINT(SEND, ERR,
  1978. ("SpxConnSendAck: Could not allocate!\n"));
  1979. }
  1980. }
  1981. #if DBG
  1982. else
  1983. {
  1984. DBGPRINT(SEND, DBG,
  1985. ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
  1986. }
  1987. #endif
  1988. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1989. // Send it.
  1990. if (pPkt != NULL)
  1991. {
  1992. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  1993. // Send the packet
  1994. SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
  1995. }
  1996. return;
  1997. }
  1998. BOOLEAN
  1999. SpxConnProcessAck(
  2000. IN PSPX_CONN_FILE pSpxConnFile,
  2001. IN PIPXSPX_HDR pIpxSpxHdr,
  2002. IN CTELockHandle lockHandle
  2003. )
  2004. /*++
  2005. Routine Description:
  2006. !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
  2007. Arguments:
  2008. pSpxConnFile - Pointer to a transport address file object.
  2009. Return Value:
  2010. --*/
  2011. {
  2012. PNDIS_PACKET pPkt;
  2013. PREQUEST pRequest;
  2014. PSPX_SEND_RESD pSendResd;
  2015. CTELockHandle interLockHandle;
  2016. USHORT seqNum = 0, ackNum;
  2017. int numDerefs = 0;
  2018. BOOLEAN fLastPkt, lockHeld = TRUE, fAbort = FALSE,
  2019. fResetRetryTimer, fResendPkt = FALSE, fResetSendQueue = FALSE;
  2020. PNDIS_BUFFER NdisBuf, NdisBuf2;
  2021. ULONG BufLen = 0;
  2022. if (pIpxSpxHdr != NULL)
  2023. {
  2024. GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
  2025. GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
  2026. // Ack numbers should already be set in connection!
  2027. if (SPX2_CONN(pSpxConnFile))
  2028. {
  2029. switch (SPX_SEND_STATE(pSpxConnFile))
  2030. {
  2031. case SPX_SEND_RETRYWD:
  2032. // Did we receive an ack for pending data? If so, we goto
  2033. // idle and process the ack.
  2034. if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
  2035. (UNSIGNED_GREATER_WITH_WRAP(
  2036. pSpxConnFile->scf_RecdAckNum,
  2037. pSendResd->sr_SeqNum)))
  2038. {
  2039. DBGPRINT(SEND, ERR,
  2040. ("SpxConnProcessAck: Data acked RETRYWD %lx.%lx!\n",
  2041. pSpxConnFile, pSendResd->sr_SeqNum));
  2042. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  2043. SpxConnFileTransferReference(
  2044. pSpxConnFile,
  2045. CFREF_ERRORSTATE,
  2046. CFREF_VERIFY);
  2047. numDerefs++;
  2048. }
  2049. else
  2050. {
  2051. // Ok, we received an ack for our probe retry, goto
  2052. // renegotiate packet size.
  2053. // For this both sides must have negotiated size to begin with.
  2054. // If they did not, we go on to retrying the data packet.
  2055. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
  2056. {
  2057. pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
  2058. if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
  2059. (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
  2060. {
  2061. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2062. DBGPRINT(SEND, DBG3,
  2063. ("SpxConnProcessAck: %lx MIN RENEG SIZE\n",
  2064. pSpxConnFile));
  2065. }
  2066. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
  2067. DBGPRINT(SEND, DBG3,
  2068. ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
  2069. pSpxConnFile));
  2070. }
  2071. else
  2072. {
  2073. DBGPRINT(SEND, ERR,
  2074. ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
  2075. pSpxConnFile,
  2076. pSpxConnFile->scf_Flags));
  2077. // Reset count to be
  2078. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2079. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
  2080. }
  2081. }
  2082. break;
  2083. case SPX_SEND_RENEG:
  2084. // We better have a data packet in the list.
  2085. CTEAssert(pSpxConnFile->scf_SendSeqListHead);
  2086. #if DBG
  2087. if ((pIpxSpxHdr->hdr_ConnCtrl &
  2088. (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
  2089. (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2))
  2090. {
  2091. DBGPRINT(SEND, DBG3,
  2092. ("SpxConnProcessAck: %lx.%lx.%lx RENEGACK SEQNUM %lx ACKNUM %lx EXPSEQ %lx\n",
  2093. pSpxConnFile,
  2094. pIpxSpxHdr->hdr_ConnCtrl,
  2095. SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT),
  2096. seqNum,
  2097. ackNum,
  2098. (pSpxConnFile->scf_SendSeqListHead->sr_SeqNum + 1)));
  2099. }
  2100. #endif
  2101. // Verify we received an RR ack. If so, we set state to
  2102. // SEND_RETRY3. First repacketize if we need to.
  2103. if ((SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT)) &&
  2104. ((pIpxSpxHdr->hdr_ConnCtrl &
  2105. (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
  2106. (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)))
  2107. {
  2108. DBGPRINT(SEND, DBG3,
  2109. ("SpxConnProcessAck: RENEG! NEW %lx.%lx!\n",
  2110. pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
  2111. // Dont allow anymore reneg packet acks to be looked at.
  2112. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
  2113. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2114. // Also set the new send sequence number.
  2115. pSpxConnFile->scf_SendSeqNum =
  2116. (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1);
  2117. // Get the max packet size we will really use. Retry timer
  2118. // could have sent other sizes by now, so we can't depend
  2119. // on whats set.
  2120. // Remember max packet size in connection.
  2121. GETSHORT2SHORT(
  2122. &pSpxConnFile->scf_MaxPktSize, &pIpxSpxHdr->hdr_NegSize);
  2123. // Basic sanity checking on the max packet size.
  2124. if (pSpxConnFile->scf_MaxPktSize < SPX_NEG_MIN)
  2125. pSpxConnFile->scf_MaxPktSize = SPX_NEG_MIN;
  2126. // Get ready to reset the send queue.
  2127. fResetSendQueue = TRUE;
  2128. DBGPRINT(SEND, DBG3,
  2129. ("SpxConnProcessAck: RENEG DONE : RETRY3 %lx.%lx MP %lx!\n",
  2130. pSpxConnFile,
  2131. pSpxConnFile->scf_SendSeqNum,
  2132. pSpxConnFile->scf_MaxPktSize));
  2133. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
  2134. }
  2135. else
  2136. {
  2137. DBGPRINT(SEND, DBG3,
  2138. ("SpxConnProcessAck: DUPLICATE RENEG ACK %lx!\n",
  2139. pSpxConnFile));
  2140. }
  2141. break;
  2142. case SPX_SEND_RETRY:
  2143. case SPX_SEND_RETRY2:
  2144. case SPX_SEND_RETRY3:
  2145. if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
  2146. (UNSIGNED_GREATER_WITH_WRAP(
  2147. pSpxConnFile->scf_RecdAckNum,
  2148. pSendResd->sr_SeqNum)))
  2149. {
  2150. DBGPRINT(SEND, DBG,
  2151. ("SpxConnProcessAck: Data acked %lx.%lx!\n",
  2152. pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
  2153. #if DBG
  2154. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
  2155. {
  2156. DBGPRINT(SEND, DBG3,
  2157. ("SpxConnProcessAck: CONN RESTORED %lx.%lx!\n",
  2158. pSpxConnFile, pSendResd->sr_SeqNum));
  2159. }
  2160. #endif
  2161. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  2162. SpxConnFileTransferReference(
  2163. pSpxConnFile,
  2164. CFREF_ERRORSTATE,
  2165. CFREF_VERIFY);
  2166. numDerefs++;
  2167. }
  2168. break;
  2169. case SPX_SEND_WD:
  2170. // Ok, we received an ack for our watchdog. Done.
  2171. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  2172. numDerefs++;
  2173. SpxConnFileTransferReference(
  2174. pSpxConnFile,
  2175. CFREF_ERRORSTATE,
  2176. CFREF_VERIFY);
  2177. break;
  2178. default:
  2179. break;
  2180. }
  2181. #if DBG
  2182. if (seqNum != 0)
  2183. {
  2184. // We have a nack, which contains an implicit ack.
  2185. // Instead of nack processing, what we do is we resend a
  2186. // packet left unacked after ack processing. ONLY if we
  2187. // either enter the loop below (fResetRetryTimer is FALSE)
  2188. // or if seqNum is non-zero (SPX2 only NACK)
  2189. }
  2190. #endif
  2191. }
  2192. }
  2193. // Once our numbers are updated, we check to see if any of our packets
  2194. // have been acked.
  2195. fResetRetryTimer = TRUE;
  2196. while (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
  2197. ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) ||
  2198. (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE) ||
  2199. fResetSendQueue) &&
  2200. (UNSIGNED_GREATER_WITH_WRAP(
  2201. pSpxConnFile->scf_RecdAckNum,
  2202. pSendResd->sr_SeqNum)))
  2203. {
  2204. // Reset retry timer
  2205. if (fResetRetryTimer)
  2206. {
  2207. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
  2208. {
  2209. // This will either successfully restart or not affect the timer
  2210. // if it is currently running.
  2211. SpxTimerCancelEvent(
  2212. pSpxConnFile->scf_RTimerId,
  2213. TRUE);
  2214. pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
  2215. }
  2216. fResetRetryTimer = FALSE;
  2217. }
  2218. // Update the retry seq num.
  2219. pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
  2220. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  2221. pSendResd, NDIS_PACKET, ProtocolReserved);
  2222. pRequest = pSendResd->sr_Request;
  2223. #if DBG
  2224. if (fResetSendQueue)
  2225. {
  2226. DBGPRINT(SEND, ERR,
  2227. ("SpxConnProcessAck: Data acked RENEG %lx.%lx!\n",
  2228. pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
  2229. }
  2230. #endif
  2231. DBGPRINT(SEND, DBG,
  2232. ("%lx Acked\n", pSendResd->sr_SeqNum));
  2233. DBGPRINT(SEND, DBG,
  2234. ("SpxConnProcessAck: %lx Seq %lx Acked Sr %lx Req %lx %lx.%lx\n",
  2235. pSpxConnFile,
  2236. pSendResd->sr_SeqNum,
  2237. pSendResd,
  2238. pRequest, REQUEST_STATUS(pRequest),
  2239. REQUEST_INFORMATION(pRequest)));
  2240. // If this packet is the last one comprising this request, remove request
  2241. // from queue. Calculate retry time.
  2242. fLastPkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_LASTPKT) != 0);
  2243. if ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) &&
  2244. ((pSendResd->sr_State & SPX_SENDPKT_REXMIT) == 0) &&
  2245. ((pSendResd->sr_SeqNum + 1) == pSpxConnFile->scf_RecdAckNum))
  2246. {
  2247. LARGE_INTEGER li, ntTime;
  2248. int value;
  2249. // This is the packet which is being acked. Adjust round trip
  2250. // timer.
  2251. li = pSendResd->sr_SentTime;
  2252. if (li.LowPart && li.HighPart)
  2253. {
  2254. KeQuerySystemTime(&ntTime);
  2255. // Get the difference
  2256. ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
  2257. // Convert to milliseconds. If the highpart is 0, we
  2258. // take a shortcut.
  2259. if (ntTime.HighPart == 0)
  2260. {
  2261. value = ntTime.LowPart/10000;
  2262. }
  2263. else
  2264. {
  2265. ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
  2266. value = ntTime.LowPart << 4;
  2267. }
  2268. //
  2269. // 55280
  2270. // calculate only if required.
  2271. //
  2272. if (0 == PARAM(CONFIG_DISABLE_RTT)) {
  2273. // Set new time
  2274. SpxCalculateNewT1(pSpxConnFile, value);
  2275. }
  2276. }
  2277. }
  2278. if (fLastPkt)
  2279. {
  2280. // Set status
  2281. REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
  2282. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  2283. // Remove creation reference
  2284. --(REQUEST_INFORMATION(pRequest));
  2285. DBGPRINT(SEND, DBG,
  2286. ("SpxConnProcessAck: LASTSEQ # %lx for Req %lx with %lx.%lx\n",
  2287. pSendResd->sr_SeqNum,
  2288. pRequest, REQUEST_STATUS(pRequest),
  2289. REQUEST_INFORMATION(pRequest)));
  2290. CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
  2291. }
  2292. // Dequeue the packet
  2293. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0);
  2294. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  2295. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
  2296. {
  2297. // Dereference request for the dequeing of the packet
  2298. --(REQUEST_INFORMATION(pRequest));
  2299. DBGPRINT(SEND, DBG,
  2300. ("SpxConnProcessAck: Request %lx with %lx.%lx\n",
  2301. pRequest, REQUEST_STATUS(pRequest),
  2302. REQUEST_INFORMATION(pRequest)));
  2303. // Free the packet
  2304. SpxPktSendRelease(pPkt);
  2305. }
  2306. else
  2307. {
  2308. // Packet owned by IPX. What do we do now? Set acked pkt so request
  2309. // gets dereferenced in send completion. Note that the packet is already
  2310. // off the queue and is floating at this point.
  2311. DBGPRINT(SEND, DBG,
  2312. ("SpxConnProcessAck: IPXOWNS Pkt %lx with %lx.%lx\n",
  2313. pPkt, pRequest, REQUEST_STATUS(pRequest)));
  2314. pSendResd->sr_State |= SPX_SENDPKT_ACKEDPKT;
  2315. }
  2316. if (SPX2_CONN(pSpxConnFile) &&
  2317. (REQUEST_MINOR_FUNCTION(pRequest) == TDI_DISCONNECT) &&
  2318. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL))
  2319. {
  2320. SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ORDREL_ACKED);
  2321. // If we had received an ordrel in the meantime, we need
  2322. // to disconnect.
  2323. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
  2324. {
  2325. fAbort = TRUE;
  2326. }
  2327. }
  2328. // All packets comprising a request have been acked!
  2329. if (REQUEST_INFORMATION(pRequest) == 0)
  2330. {
  2331. CTELockHandle lockHandleInter;
  2332. if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
  2333. {
  2334. PTDI_REQUEST_KERNEL_SEND pParam;
  2335. pParam = (PTDI_REQUEST_KERNEL_SEND)
  2336. REQUEST_PARAMETERS(pRequest);
  2337. REQUEST_INFORMATION(pRequest) = pParam->SendLength;
  2338. DBGPRINT(SEND, DBG,
  2339. ("SpxSendComplete: QForComp Request %lx with %lx.%lx\n",
  2340. pRequest, REQUEST_STATUS(pRequest),
  2341. REQUEST_INFORMATION(pRequest)));
  2342. // Request is done. Move to completion list.
  2343. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  2344. InsertTailList(
  2345. &pSpxConnFile->scf_ReqDoneLinkage,
  2346. REQUEST_LINKAGE(pRequest));
  2347. // If connection is not already in recv queue, put it in
  2348. // there.
  2349. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  2350. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  2351. }
  2352. else
  2353. {
  2354. DBGPRINT(SEND, DBG,
  2355. ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
  2356. pRequest, REQUEST_STATUS(pRequest),
  2357. REQUEST_INFORMATION(pRequest)));
  2358. // Set the request in the connection, and deref for it.
  2359. InsertTailList(
  2360. &pSpxConnFile->scf_DiscLinkage,
  2361. REQUEST_LINKAGE(pRequest));
  2362. numDerefs++;
  2363. }
  2364. }
  2365. #if DBG
  2366. else if (fLastPkt)
  2367. {
  2368. DBGPRINT(RECEIVE, DBG,
  2369. ("spxConnProcessAck: ReqFloating %lx.%lx\n",
  2370. pSpxConnFile, pRequest));
  2371. }
  2372. #endif
  2373. }
  2374. // See if we reset the send queue and repacketize.
  2375. if (fResetSendQueue)
  2376. {
  2377. // Reset send queue and repacketize only if pkts left unacked.
  2378. if (pSpxConnFile->scf_SendSeqListHead)
  2379. {
  2380. DBGPRINT(SEND, DBG3,
  2381. ("SpxConnProcessAck: Resetting send queue %lx.%lx!\n",
  2382. pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
  2383. spxConnResetSendQueue(pSpxConnFile);
  2384. DBGPRINT(SEND, DBG3,
  2385. ("SpxConnProcessAck: Repacketizing %lx.%lx!\n",
  2386. pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
  2387. SpxConnPacketize(pSpxConnFile, FALSE, lockHandle);
  2388. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  2389. }
  2390. else
  2391. {
  2392. // We just go back to idle state now.
  2393. DBGPRINT(SEND, ERR,
  2394. ("SpxConnProcessAck: All packets acked reneg ack! %lx.%lx!\n",
  2395. pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
  2396. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  2397. numDerefs++;
  2398. SpxConnFileTransferReference(
  2399. pSpxConnFile,
  2400. CFREF_ERRORSTATE,
  2401. CFREF_VERIFY);
  2402. }
  2403. }
  2404. // See if we resend a packet.
  2405. if ((seqNum != 0) &&
  2406. !fAbort &&
  2407. ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
  2408. (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
  2409. ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0))
  2410. {
  2411. PIPXSPX_HDR pSendHdr;
  2412. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  2413. pSendResd, NDIS_PACKET, ProtocolReserved);
  2414. //
  2415. // Get the MDL that points to the IPX/SPX header. (the second one)
  2416. //
  2417. NdisQueryPacket(pPkt, NULL, NULL, &NdisBuf, NULL);
  2418. NdisGetNextBuffer(NdisBuf, &NdisBuf2);
  2419. NdisQueryBuffer(NdisBuf2, (PUCHAR) &pSendHdr, &BufLen);
  2420. #if OWN_PKT_POOLS
  2421. pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
  2422. NDIS_PACKET_SIZE +
  2423. sizeof(SPX_SEND_RESD) +
  2424. IpxInclHdrOffset);
  2425. #endif
  2426. // Set ack bit in packet. pSendResd initialized at beginning.
  2427. pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
  2428. // We are going to resend this packet
  2429. pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
  2430. SPX_SENDPKT_ACKREQ |
  2431. SPX_SENDPKT_REXMIT);
  2432. fResendPkt = TRUE;
  2433. }
  2434. // Push into packetize only if we received an ack. And if there arent any
  2435. // packets already waiting. Probably retransmit happening.
  2436. if (!fAbort &&
  2437. SPX_CONN_ACTIVE(pSpxConnFile) &&
  2438. (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
  2439. (pSpxConnFile->scf_ReqPkt != NULL) &&
  2440. (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_PKTQ)) &&
  2441. ((pSpxConnFile->scf_SendSeqListHead) == NULL) &&
  2442. (!SPX2_CONN(pSpxConnFile) ||
  2443. ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED) &&
  2444. (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL))))
  2445. {
  2446. DBGPRINT(RECEIVE, DBG,
  2447. ("spxConnProcessAck: Recd ack pktizng\n", pSpxConnFile));
  2448. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
  2449. SpxConnFileLockReference(pSpxConnFile, CFREF_PKTIZE);
  2450. CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
  2451. SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile);
  2452. CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
  2453. }
  2454. else if (fAbort)
  2455. {
  2456. // Set IDISC flag so Abortive doesnt reindicate.
  2457. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
  2458. spxConnAbortiveDisc(
  2459. pSpxConnFile,
  2460. STATUS_SUCCESS,
  2461. SPX_CALL_RECVLEVEL,
  2462. lockHandle,
  2463. FALSE); // [SA] bug #15249
  2464. lockHeld = FALSE;
  2465. }
  2466. if (lockHeld)
  2467. {
  2468. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  2469. }
  2470. if (fResendPkt)
  2471. {
  2472. DBGPRINT(SEND, DBG3,
  2473. ("SpxConnProcessAck: Resend pkt on %lx.%lx\n",
  2474. pSpxConnFile, pSendResd->sr_SeqNum));
  2475. ++SpxDevice->dev_Stat.DataFramesResent;
  2476. ExInterlockedAddLargeStatistic(
  2477. &SpxDevice->dev_Stat.DataFrameBytesResent,
  2478. pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
  2479. SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
  2480. }
  2481. while (numDerefs-- > 0)
  2482. {
  2483. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2484. }
  2485. return(TRUE);
  2486. }
  2487. VOID
  2488. SpxConnProcessRenegReq(
  2489. IN PSPX_CONN_FILE pSpxConnFile,
  2490. IN PIPXSPX_HDR pIpxSpxHdr,
  2491. IN PIPX_LOCAL_TARGET pRemoteAddr,
  2492. IN CTELockHandle lockHandle
  2493. )
  2494. /*++
  2495. Routine Description:
  2496. !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
  2497. Arguments:
  2498. pSpxConnFile - Pointer to a transport address file object.
  2499. Return Value:
  2500. --*/
  2501. {
  2502. USHORT seqNum, ackNum, allocNum, maxPktSize;
  2503. PSPX_SEND_RESD pSendResd;
  2504. PNDIS_PACKET pPkt = NULL;
  2505. // The remote sent us a renegotiate request. We need to send an ack back
  2506. // ONLY if we have not acked a data packet with that same sequence number.
  2507. // This is guaranteed by the fact that we will not accept the reneg request
  2508. // if we have already acked a data packet with the same seq num, as our
  2509. // receive seq number would be incremented already.
  2510. //
  2511. // Note that if we have pending send packets we may end up doing a reneg
  2512. // also.
  2513. GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
  2514. GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
  2515. GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
  2516. GETSHORT2SHORT(&maxPktSize, &pIpxSpxHdr->hdr_PktLen);
  2517. // If the received seq num is less than the expected receive sequence number
  2518. // we ignore this request.
  2519. if (!UNSIGNED_GREATER_WITH_WRAP(
  2520. seqNum,
  2521. pSpxConnFile->scf_RecvSeqNum) &&
  2522. (seqNum != pSpxConnFile->scf_RecvSeqNum))
  2523. {
  2524. DBGPRINT(SEND, DBG3,
  2525. ("SpxConnProcessRenegReq: %lx ERROR RENSEQ %lx RECVSEQ %lx %lx\n",
  2526. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
  2527. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  2528. return;
  2529. }
  2530. DBGPRINT(SEND, DBG3,
  2531. ("SpxConnProcessRenegReq: %lx RENSEQ %lx RECVSEQ %lx MAXPKT %lx\n",
  2532. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum, maxPktSize));
  2533. // Set ack numbers for connection.
  2534. SPX_SET_ACKNUM(
  2535. pSpxConnFile, ackNum, allocNum);
  2536. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
  2537. pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
  2538. // Set RenegAckAckNum before calling buildrrack. If a previous reneg
  2539. // request was received with a greater maxpktsize, send an ack with
  2540. // that maxpktsize.
  2541. if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD))
  2542. {
  2543. pSpxConnFile->scf_RenegAckAckNum = pSpxConnFile->scf_RecvSeqNum;
  2544. pSpxConnFile->scf_RenegMaxPktSize= maxPktSize;
  2545. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD);
  2546. DBGPRINT(SEND, DBG3,
  2547. ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM CURRENT %lx\n",
  2548. pSpxConnFile,
  2549. pSpxConnFile->scf_SentAllocNum));
  2550. // Adjust sentallocnum now that recvseqnum might have moved up.
  2551. pSpxConnFile->scf_SentAllocNum +=
  2552. (seqNum - pSpxConnFile->scf_RenegAckAckNum);
  2553. DBGPRINT(SEND, DBG3,
  2554. ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM ADJUSTED %lx\n",
  2555. pSpxConnFile,
  2556. pSpxConnFile->scf_SentAllocNum));
  2557. }
  2558. // The recvseqnum for the reneg is always >= the renegackacknum.
  2559. pSpxConnFile->scf_RecvSeqNum = seqNum;
  2560. DBGPRINT(SEND, DBG3,
  2561. ("SpxConnProcessRenegReq: %lx RESET RECVSEQ %lx SavedACKACK %lx\n",
  2562. pSpxConnFile,
  2563. pSpxConnFile->scf_RecvSeqNum,
  2564. pSpxConnFile->scf_RenegAckAckNum));
  2565. // Build and send an ack.
  2566. SpxPktBuildRrAck(
  2567. pSpxConnFile,
  2568. &pPkt,
  2569. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
  2570. pSpxConnFile->scf_RenegMaxPktSize);
  2571. if (pPkt != NULL)
  2572. {
  2573. SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
  2574. }
  2575. #if DBG
  2576. else
  2577. {
  2578. // Log error
  2579. DBGPRINT(SEND, ERR,
  2580. ("SpxConnSendRenegReqAck: Could not allocate!\n"));
  2581. }
  2582. #endif
  2583. // Check if we are an ack/nack packet in which case call process
  2584. // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
  2585. SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
  2586. if (pPkt != NULL)
  2587. {
  2588. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  2589. // Send the packet
  2590. SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
  2591. }
  2592. return;
  2593. }
  2594. VOID
  2595. SpxConnProcessOrdRel(
  2596. IN PSPX_CONN_FILE pSpxConnFile,
  2597. IN CTELockHandle lockHandle
  2598. )
  2599. /*++
  2600. Routine Description:
  2601. !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
  2602. Arguments:
  2603. pSpxConnFile - Pointer to a transport address file object.
  2604. Return Value:
  2605. --*/
  2606. {
  2607. PSPX_SEND_RESD pSendResd;
  2608. PVOID pDiscHandlerCtx;
  2609. PTDI_IND_DISCONNECT pDiscHandler = NULL;
  2610. int numDerefs = 0;
  2611. PNDIS_PACKET pPkt = NULL;
  2612. BOOLEAN lockHeld = TRUE, fAbort = FALSE;
  2613. if (SPX_CONN_ACTIVE(pSpxConnFile))
  2614. {
  2615. if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ORDREL_ACKED)
  2616. {
  2617. fAbort = TRUE;
  2618. }
  2619. // Send an ack if one was asked for. And we are done with this pkt
  2620. // Update seq numbers and stuff.
  2621. SPX_SET_RECVNUM(pSpxConnFile, FALSE);
  2622. // Build and send an ack for this. Ordinary spx2 ack.
  2623. SpxPktBuildAck(
  2624. pSpxConnFile,
  2625. &pPkt,
  2626. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
  2627. FALSE,
  2628. 0);
  2629. if (pPkt != NULL)
  2630. {
  2631. // We don't queue this pkt in as we have the ABORT flag set in
  2632. // the packet, which implies the pkt is already dequeued.
  2633. // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
  2634. // Reference conn for the pkt.
  2635. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  2636. }
  2637. // Get disconnect handler if we have one. And have not indicated
  2638. // abortive disconnect on this connection to afd.
  2639. //
  2640. // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
  2641. //
  2642. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC) &&
  2643. !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
  2644. {
  2645. // Yeah, we set the flag regardless of whether a handler is
  2646. // present.
  2647. pDiscHandler =pSpxConnFile->scf_AddrFile->saf_DiscHandler;
  2648. pDiscHandlerCtx=pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
  2649. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC);
  2650. }
  2651. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  2652. // Indicate disconnect to afd.
  2653. if (pDiscHandler != NULL)
  2654. {
  2655. (*pDiscHandler)(
  2656. pDiscHandlerCtx,
  2657. pSpxConnFile->scf_ConnCtx,
  2658. 0, // Disc data
  2659. NULL,
  2660. 0, // Disc info
  2661. NULL,
  2662. TDI_DISCONNECT_RELEASE);
  2663. }
  2664. // We abort any receives here if !fAbort else we abort conn.
  2665. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  2666. if (fAbort)
  2667. {
  2668. // Set IDISC flag so Abortive doesnt reindicate.
  2669. SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
  2670. spxConnAbortiveDisc(
  2671. pSpxConnFile,
  2672. STATUS_SUCCESS,
  2673. SPX_CALL_RECVLEVEL,
  2674. lockHandle,
  2675. FALSE); // [SA] bug #15249
  2676. lockHeld = FALSE;
  2677. }
  2678. else
  2679. {
  2680. // Go through and kill all pending requests.
  2681. spxConnAbortRecvs(
  2682. pSpxConnFile,
  2683. STATUS_REMOTE_DISCONNECT,
  2684. SPX_CALL_RECVLEVEL,
  2685. lockHandle);
  2686. lockHeld = FALSE;
  2687. }
  2688. }
  2689. if (lockHeld)
  2690. {
  2691. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  2692. }
  2693. if (pPkt != NULL)
  2694. {
  2695. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  2696. // Send the packet
  2697. SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
  2698. }
  2699. while (numDerefs-- > 0)
  2700. {
  2701. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2702. }
  2703. return;
  2704. }
  2705. VOID
  2706. SpxConnProcessIDisc(
  2707. IN PSPX_CONN_FILE pSpxConnFile,
  2708. IN CTELockHandle lockHandle
  2709. )
  2710. /*++
  2711. Routine Description:
  2712. !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
  2713. Arguments:
  2714. pSpxConnFile - Pointer to a transport address file object.
  2715. Return Value:
  2716. --*/
  2717. {
  2718. PSPX_SEND_RESD pSendResd;
  2719. PNDIS_PACKET pPkt = NULL;
  2720. PNDIS_BUFFER NdisBuf, NdisBuf2;
  2721. ULONG BufLen = 0;
  2722. SPX_SET_RECVNUM(pSpxConnFile, FALSE);
  2723. // Build and send an ack for the idisc. Need to modify data type
  2724. // and reset sys bit on ack.
  2725. // BUG #12344 - Fixing this led to the problem where we queue in
  2726. // the pkt below, but AbortSends could already have been called
  2727. // => this packet stays on queue without a ref, conn gets freed
  2728. // underneath, and in the sendcomplete we crash when this send
  2729. // completes.
  2730. //
  2731. // Fix is to setup this pkt as a aborted pkt to start with.
  2732. SpxPktBuildAck(
  2733. pSpxConnFile,
  2734. &pPkt,
  2735. SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
  2736. FALSE,
  2737. 0);
  2738. if (pPkt != NULL)
  2739. {
  2740. PIPXSPX_HDR pSendHdr;
  2741. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  2742. //
  2743. // Get the MDL that points to the IPX/SPX header. (the second one)
  2744. //
  2745. NdisQueryPacket(pPkt, NULL, NULL, &NdisBuf, NULL);
  2746. NdisGetNextBuffer(NdisBuf, &NdisBuf2);
  2747. NdisQueryBuffer(NdisBuf2, (PUCHAR) &pSendHdr, &BufLen);
  2748. #if OWN_PKT_POOLS
  2749. pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
  2750. NDIS_PACKET_SIZE +
  2751. sizeof(SPX_SEND_RESD) +
  2752. IpxInclHdrOffset);
  2753. #endif
  2754. pSendHdr->hdr_ConnCtrl &= ~SPX_CC_SYS;
  2755. pSendHdr->hdr_DataType = SPX2_DT_IDISC_ACK;
  2756. // We don't queue this pkt in as we have the ABORT flag set in
  2757. // the packet, which implies the pkt is already dequeued.
  2758. // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
  2759. // Reference conn for the pkt.
  2760. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  2761. }
  2762. // We better not have any received pkts, we ignore disconnect
  2763. // pkts when that happens.
  2764. CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
  2765. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  2766. #if DBG
  2767. if (pSpxConnFile->scf_SendSeqListHead != NULL)
  2768. {
  2769. DBGPRINT(CONNECT, DBG1,
  2770. ("SpxConnDiscPacket: DATA/DISC %lx.%lx.%lx\n",
  2771. pSpxConnFile,
  2772. pSpxConnFile->scf_SendListHead,
  2773. pSpxConnFile->scf_SendSeqListHead));
  2774. }
  2775. #endif
  2776. // Call abortive disconnect on connection.
  2777. //
  2778. // [SA] bug #15249
  2779. // This is an informed disconnect, hence pass DISCONNECT_RELEASE to AFD (TRUE in last param)
  2780. //
  2781. //
  2782. // We pass true only in the case of an SPX connection. SPX2 connections follow the
  2783. // exact semantics of Informed Disconnect.
  2784. //
  2785. if (!SPX2_CONN(pSpxConnFile)) {
  2786. spxConnAbortiveDisc(
  2787. pSpxConnFile,
  2788. STATUS_REMOTE_DISCONNECT,
  2789. SPX_CALL_RECVLEVEL,
  2790. lockHandle,
  2791. TRUE);
  2792. } else {
  2793. spxConnAbortiveDisc(
  2794. pSpxConnFile,
  2795. STATUS_REMOTE_DISCONNECT,
  2796. SPX_CALL_RECVLEVEL,
  2797. lockHandle,
  2798. FALSE);
  2799. }
  2800. if (pPkt != NULL)
  2801. {
  2802. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  2803. // Send the packet
  2804. SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
  2805. }
  2806. return;
  2807. }
  2808. VOID
  2809. spxConnResetSendQueue(
  2810. IN PSPX_CONN_FILE pSpxConnFile
  2811. )
  2812. /*++
  2813. Routine Description:
  2814. Arguments:
  2815. Return Value:
  2816. --*/
  2817. {
  2818. PSPX_SEND_RESD pSendResd;
  2819. PREQUEST pRequest;
  2820. PNDIS_PACKET pPkt;
  2821. pSendResd = pSpxConnFile->scf_SendSeqListHead;
  2822. CTEAssert(pSendResd != NULL);
  2823. pRequest = pSendResd->sr_Request;
  2824. // Reset the current send request values
  2825. pSpxConnFile->scf_ReqPkt = pSendResd->sr_Request;
  2826. pSpxConnFile->scf_ReqPktOffset = pSendResd->sr_Offset;
  2827. pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
  2828. if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
  2829. {
  2830. PTDI_REQUEST_KERNEL_SEND pParam;
  2831. pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
  2832. DBGPRINT(SEND, DBG3,
  2833. ("spxConnResetSendQueue: %lx.%lx.%lx Reset SEND Req to %lx.%lx\n",
  2834. pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
  2835. pRequest, pParam->SendLength));
  2836. // Set parameters in connection for another go. Size parameter is
  2837. // original size - offset at this point.
  2838. pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
  2839. pSpxConnFile->scf_ReqPktSize = pParam->SendLength -
  2840. pSpxConnFile->scf_ReqPktOffset;
  2841. }
  2842. else
  2843. {
  2844. PTDI_REQUEST_KERNEL_DISCONNECT pParam;
  2845. DBGPRINT(SEND, ERR,
  2846. ("spxConnResetSendQueue: %lx.%lx.%lx Reset DISC Req to %lx\n",
  2847. pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
  2848. pRequest));
  2849. DBGPRINT(SEND, ERR,
  2850. ("spxConnResetSendQueue: DISC Request %lx with %lx.%lx\n",
  2851. pRequest, REQUEST_STATUS(pRequest),
  2852. REQUEST_INFORMATION(pRequest)));
  2853. pParam =
  2854. (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
  2855. pSpxConnFile->scf_ReqPktOffset = 0;
  2856. pSpxConnFile->scf_ReqPktSize = 0;
  2857. pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
  2858. if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
  2859. {
  2860. pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
  2861. }
  2862. }
  2863. DBGPRINT(SEND, DBG3,
  2864. ("spxConnResetSendQueue: Seq Num for %lx is now %lx\n",
  2865. pSpxConnFile, pSpxConnFile->scf_SendSeqNum));
  2866. // When we are trying to abort a pkt and it is in use by ipx, we simply let
  2867. // it float.
  2868. do
  2869. {
  2870. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  2871. pSendResd, NDIS_PACKET, ProtocolReserved);
  2872. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
  2873. pRequest = pSendResd->sr_Request;
  2874. CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
  2875. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  2876. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
  2877. {
  2878. if (--(REQUEST_INFORMATION(pRequest)) == 0)
  2879. {
  2880. DBGPRINT(SEND, DBG,
  2881. ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
  2882. pRequest, REQUEST_STATUS(pRequest),
  2883. REQUEST_INFORMATION(pRequest)));
  2884. KeBugCheck(0);
  2885. }
  2886. // Free the packet
  2887. SpxPktSendRelease(pPkt);
  2888. }
  2889. else
  2890. {
  2891. // We let send completion know that this packet is to be aborted.
  2892. pSendResd->sr_State |= SPX_SENDPKT_ABORT;
  2893. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  2894. }
  2895. } while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL);
  2896. return;
  2897. }
  2898. VOID
  2899. spxConnAbortSendPkt(
  2900. IN PSPX_CONN_FILE pSpxConnFile,
  2901. IN PSPX_SEND_RESD pSendResd,
  2902. IN SPX_CALL_LEVEL CallLevel,
  2903. IN CTELockHandle LockHandleConn
  2904. )
  2905. /*++
  2906. Routine Description:
  2907. Called to abort either a sequenced or a non-sequenced packet ONLY from
  2908. send completion.
  2909. Arguments:
  2910. Return Value:
  2911. --*/
  2912. {
  2913. LIST_ENTRY ReqList, *p;
  2914. PREQUEST pRequest;
  2915. PNDIS_PACKET pPkt;
  2916. int numDerefs = 0;
  2917. InitializeListHead(&ReqList);
  2918. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  2919. pSendResd, NDIS_PACKET, ProtocolReserved);
  2920. if ((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0)
  2921. {
  2922. pRequest = pSendResd->sr_Request;
  2923. CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
  2924. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
  2925. if (--(REQUEST_INFORMATION(pRequest)) == 0)
  2926. {
  2927. // Remove request from list its on
  2928. // BUG #11626 - request is already removed from list.
  2929. // RemoveEntryList(REQUEST_LINKAGE(pRequest));
  2930. if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
  2931. {
  2932. DBGPRINT(SEND, DBG,
  2933. ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
  2934. pRequest, REQUEST_STATUS(pRequest),
  2935. REQUEST_INFORMATION(pRequest)));
  2936. if (CallLevel == SPX_CALL_RECVLEVEL)
  2937. {
  2938. CTELockHandle lockHandleInter;
  2939. // Request is done. Move to completion list.
  2940. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  2941. InsertTailList(
  2942. &pSpxConnFile->scf_ReqDoneLinkage,
  2943. REQUEST_LINKAGE(pRequest));
  2944. // If connection is not already in recv queue, put it in
  2945. // there.
  2946. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  2947. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  2948. }
  2949. else
  2950. {
  2951. InsertTailList(
  2952. &ReqList,
  2953. REQUEST_LINKAGE(pRequest));
  2954. }
  2955. }
  2956. else
  2957. {
  2958. DBGPRINT(SEND, DBG,
  2959. ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
  2960. pRequest, REQUEST_STATUS(pRequest),
  2961. REQUEST_INFORMATION(pRequest)));
  2962. // Set the request in the connection, and deref for it.
  2963. InsertTailList(
  2964. &pSpxConnFile->scf_DiscLinkage,
  2965. REQUEST_LINKAGE(pRequest));
  2966. numDerefs++;
  2967. }
  2968. }
  2969. }
  2970. // Release
  2971. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2972. // Free the packet
  2973. SpxPktSendRelease(pPkt);
  2974. SpxConnFileDereference(pSpxConnFile, CFREF_ABORTPKT);
  2975. if (!IsListEmpty(&ReqList))
  2976. {
  2977. p = RemoveHeadList(&ReqList);
  2978. pRequest = LIST_ENTRY_TO_REQUEST(p);
  2979. SpxCompleteRequest(pRequest);
  2980. numDerefs++;
  2981. }
  2982. while (numDerefs-- > 0)
  2983. {
  2984. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2985. }
  2986. return;
  2987. }
  2988. VOID
  2989. spxConnAbortSends(
  2990. IN PSPX_CONN_FILE pSpxConnFile,
  2991. IN NTSTATUS Status,
  2992. IN SPX_CALL_LEVEL CallLevel,
  2993. IN CTELockHandle LockHandleConn
  2994. )
  2995. /*++
  2996. Routine Description:
  2997. Arguments:
  2998. Return Value:
  2999. --*/
  3000. {
  3001. LIST_ENTRY ReqList, *p;
  3002. PSPX_SEND_RESD pSendResd;
  3003. PREQUEST pRequest;
  3004. PNDIS_PACKET pPkt;
  3005. int numDerefs = 0;
  3006. InitializeListHead(&ReqList);
  3007. // We better be in disconnect state, abortive/informed/orderly initiate.
  3008. CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
  3009. // Reset the current send request values
  3010. pSpxConnFile->scf_ReqPkt = NULL;
  3011. pSpxConnFile->scf_ReqPktOffset = 0;
  3012. pSpxConnFile->scf_ReqPktSize = 0;
  3013. pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
  3014. // First go through the non-seq pkt queue.Just set abort flag if owned by ipx
  3015. while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
  3016. {
  3017. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  3018. pSendResd, NDIS_PACKET, ProtocolReserved);
  3019. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) == 0);
  3020. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  3021. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
  3022. {
  3023. // Free the packet
  3024. SpxPktSendRelease(pPkt);
  3025. }
  3026. else
  3027. {
  3028. // Set abort flag and reference conn for the pkt if its not already.
  3029. // We only do this check for the non-sequenced packets.
  3030. // BUG #12344 (see SpxRecvDiscPacket())
  3031. if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) == 0)
  3032. {
  3033. pSendResd->sr_State |= SPX_SENDPKT_ABORT;
  3034. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  3035. }
  3036. }
  3037. }
  3038. // When we are trying to abort a pkt and it is in use by ipx, we simply let
  3039. // it float.
  3040. while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL)
  3041. {
  3042. pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  3043. pSendResd, NDIS_PACKET, ProtocolReserved);
  3044. CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
  3045. pRequest = pSendResd->sr_Request;
  3046. CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
  3047. SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
  3048. if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
  3049. {
  3050. if (--(REQUEST_INFORMATION(pRequest)) == 0)
  3051. {
  3052. // Remove request from list its on
  3053. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  3054. // Set status
  3055. REQUEST_STATUS(pRequest) = Status;
  3056. REQUEST_INFORMATION(pRequest) = 0;
  3057. if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
  3058. {
  3059. DBGPRINT(SEND, DBG,
  3060. ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
  3061. pRequest, REQUEST_STATUS(pRequest),
  3062. REQUEST_INFORMATION(pRequest)));
  3063. if (CallLevel == SPX_CALL_RECVLEVEL)
  3064. {
  3065. CTELockHandle lockHandleInter;
  3066. // Request is done. Move to completion list.
  3067. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  3068. InsertTailList(
  3069. &pSpxConnFile->scf_ReqDoneLinkage,
  3070. REQUEST_LINKAGE(pRequest));
  3071. // If connection is not already in recv queue, put it in
  3072. // there.
  3073. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  3074. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  3075. }
  3076. else
  3077. {
  3078. InsertTailList(
  3079. &ReqList,
  3080. REQUEST_LINKAGE(pRequest));
  3081. }
  3082. }
  3083. else
  3084. {
  3085. DBGPRINT(SEND, DBG,
  3086. ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
  3087. pRequest, REQUEST_STATUS(pRequest),
  3088. REQUEST_INFORMATION(pRequest)));
  3089. // Set the request in the connection, and deref for it.
  3090. InsertTailList(
  3091. &pSpxConnFile->scf_DiscLinkage,
  3092. REQUEST_LINKAGE(pRequest));
  3093. numDerefs++;
  3094. }
  3095. }
  3096. // Free the packet
  3097. SpxPktSendRelease(pPkt);
  3098. }
  3099. else
  3100. {
  3101. // We let send completion know that this packet is to be aborted.
  3102. pSendResd->sr_State |= SPX_SENDPKT_ABORT;
  3103. SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
  3104. }
  3105. }
  3106. // If retry timer state is on, then we need to reset and deref.
  3107. if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
  3108. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
  3109. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
  3110. {
  3111. DBGPRINT(SEND, DBG1,
  3112. ("spxConnAbortSends: When SEND ERROR STATE %lx.%lx\n",
  3113. pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
  3114. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
  3115. SpxConnFileTransferReference(
  3116. pSpxConnFile,
  3117. CFREF_ERRORSTATE,
  3118. CFREF_VERIFY);
  3119. numDerefs++;
  3120. }
  3121. // Remove creation references on all sends.
  3122. if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
  3123. {
  3124. p = pSpxConnFile->scf_ReqLinkage.Flink;
  3125. while (p != &pSpxConnFile->scf_ReqLinkage)
  3126. {
  3127. pRequest = LIST_ENTRY_TO_REQUEST(p);
  3128. p = p->Flink;
  3129. // Remove request from list its on. Its complete or abort list for it.
  3130. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  3131. // Set status
  3132. REQUEST_STATUS(pRequest) = Status;
  3133. DBGPRINT(SEND, DBG1,
  3134. ("SpxSendAbort: %lx Aborting Send Request %lx with %lx.%lx\n",
  3135. pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
  3136. REQUEST_INFORMATION(pRequest)));
  3137. if (--(REQUEST_INFORMATION(pRequest)) == 0)
  3138. {
  3139. if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
  3140. {
  3141. DBGPRINT(SEND, DBG,
  3142. ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
  3143. pRequest, REQUEST_STATUS(pRequest),
  3144. REQUEST_INFORMATION(pRequest)));
  3145. if (CallLevel == SPX_CALL_RECVLEVEL)
  3146. {
  3147. CTELockHandle lockHandleInter;
  3148. // Request is done. Move to completion list.
  3149. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  3150. InsertTailList(
  3151. &pSpxConnFile->scf_ReqDoneLinkage,
  3152. REQUEST_LINKAGE(pRequest));
  3153. // If connection is not already in recv queue, put it in
  3154. // there.
  3155. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  3156. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  3157. }
  3158. else
  3159. {
  3160. InsertTailList(
  3161. &ReqList,
  3162. REQUEST_LINKAGE(pRequest));
  3163. }
  3164. }
  3165. else
  3166. {
  3167. DBGPRINT(SEND, DBG1,
  3168. ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
  3169. pRequest, REQUEST_STATUS(pRequest),
  3170. REQUEST_INFORMATION(pRequest)));
  3171. // Set the request in the connection, and deref for it.
  3172. InsertTailList(
  3173. &pSpxConnFile->scf_DiscLinkage,
  3174. REQUEST_LINKAGE(pRequest));
  3175. numDerefs++;
  3176. }
  3177. }
  3178. #if DBG
  3179. else
  3180. {
  3181. // Let it float,
  3182. DBGPRINT(SEND, DBG1,
  3183. ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
  3184. pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
  3185. REQUEST_INFORMATION(pRequest)));
  3186. }
  3187. #endif
  3188. }
  3189. }
  3190. // Release
  3191. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  3192. while (!IsListEmpty(&ReqList))
  3193. {
  3194. p = RemoveHeadList(&ReqList);
  3195. pRequest = LIST_ENTRY_TO_REQUEST(p);
  3196. SpxCompleteRequest(pRequest);
  3197. numDerefs++;
  3198. }
  3199. while (numDerefs-- > 0)
  3200. {
  3201. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  3202. }
  3203. return;
  3204. }
  3205. VOID
  3206. spxConnAbortRecvs(
  3207. IN PSPX_CONN_FILE pSpxConnFile,
  3208. IN NTSTATUS Status,
  3209. IN SPX_CALL_LEVEL CallLevel,
  3210. IN CTELockHandle LockHandleConn
  3211. )
  3212. /*++
  3213. Routine Description:
  3214. Arguments:
  3215. Return Value:
  3216. --*/
  3217. {
  3218. LIST_ENTRY ReqList, *p;
  3219. PREQUEST pRequest;
  3220. PSPX_RECV_RESD pRecvResd;
  3221. PNDIS_PACKET pNdisPkt;
  3222. PNDIS_BUFFER pNdisBuffer;
  3223. PBYTE pData;
  3224. ULONG dataLen;
  3225. int numDerefs = 0;
  3226. InitializeListHead(&ReqList);
  3227. // We better be in disconnect state, abortive/informed/orderly initiate.
  3228. // Reset the current receive request values
  3229. pSpxConnFile->scf_CurRecvReq = NULL;
  3230. pSpxConnFile->scf_CurRecvOffset = 0;
  3231. pSpxConnFile->scf_CurRecvSize = 0;
  3232. // If we have any buffered data, abort it.
  3233. // Buffered data that is 0 bytes long (only eom) may not have a ndis
  3234. // buffer associated with it.
  3235. while ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL)
  3236. {
  3237. if ((pSpxConnFile->scf_RecvListHead = pRecvResd->rr_Next) == NULL)
  3238. {
  3239. pSpxConnFile->scf_RecvListTail = NULL;
  3240. }
  3241. pNdisPkt = (PNDIS_PACKET)
  3242. CONTAINING_RECORD(pRecvResd, NDIS_PACKET, ProtocolReserved);
  3243. DBGPRINT(RECEIVE, DBG1,
  3244. ("spxConnAbortRecvs: %lx in bufferlist on %lx\n",
  3245. pSpxConnFile, pNdisPkt));
  3246. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  3247. if (pNdisBuffer != NULL)
  3248. {
  3249. NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
  3250. CTEAssert(pData != NULL);
  3251. CTEAssert((LONG)dataLen >= 0);
  3252. SpxFreeMemory(pData);
  3253. NdisFreeBuffer(pNdisBuffer);
  3254. }
  3255. // Packet consumed. Free it up.
  3256. numDerefs++;
  3257. // Free the ndis packet
  3258. SpxPktRecvRelease(pNdisPkt);
  3259. }
  3260. // If packets are on this queue, they are waiting for transfer data to
  3261. // complete. Can't do much about that, just go and remove creation refs
  3262. // on the receives.
  3263. if (!IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
  3264. {
  3265. p = pSpxConnFile->scf_RecvLinkage.Flink;
  3266. while (p != &pSpxConnFile->scf_RecvLinkage)
  3267. {
  3268. pRequest = LIST_ENTRY_TO_REQUEST(p);
  3269. p = p->Flink;
  3270. // Remove request from list its on
  3271. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  3272. // Set status
  3273. REQUEST_STATUS(pRequest) = Status;
  3274. DBGPRINT(RECEIVE, DBG1,
  3275. ("SpxRecvAbort: Aborting Recv Request %lx with %lx.%lx\n",
  3276. pRequest, REQUEST_STATUS(pRequest),
  3277. REQUEST_INFORMATION(pRequest)));
  3278. if (REQUEST_INFORMATION(pRequest) == 0)
  3279. {
  3280. DBGPRINT(RECEIVE, DBG,
  3281. ("SpxRecvAbort: QForComp Request %lx with %lx.%lx\n",
  3282. pRequest, REQUEST_STATUS(pRequest),
  3283. REQUEST_INFORMATION(pRequest)));
  3284. if (CallLevel == SPX_CALL_RECVLEVEL)
  3285. {
  3286. CTELockHandle lockHandleInter;
  3287. // Request is done. Move to completion list.
  3288. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  3289. InsertTailList(
  3290. &pSpxConnFile->scf_RecvDoneLinkage,
  3291. REQUEST_LINKAGE(pRequest));
  3292. // If connection is not already in recv queue, put it in
  3293. // there.
  3294. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  3295. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  3296. }
  3297. else
  3298. {
  3299. InsertTailList(
  3300. &ReqList,
  3301. REQUEST_LINKAGE(pRequest));
  3302. }
  3303. }
  3304. #if DBG
  3305. else
  3306. {
  3307. // Let it float,
  3308. DBGPRINT(SEND, DBG1,
  3309. ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
  3310. pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
  3311. REQUEST_INFORMATION(pRequest)));
  3312. }
  3313. #endif
  3314. }
  3315. }
  3316. // Release
  3317. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  3318. while (!IsListEmpty(&ReqList))
  3319. {
  3320. p = RemoveHeadList(&ReqList);
  3321. pRequest = LIST_ENTRY_TO_REQUEST(p);
  3322. numDerefs++;
  3323. SpxCompleteRequest(pRequest);
  3324. }
  3325. while (numDerefs-- > 0)
  3326. {
  3327. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  3328. }
  3329. return;
  3330. }
  3331. #if 0
  3332. VOID
  3333. spxConnResendPkts(
  3334. IN PSPX_CONN_FILE pSpxConnFile,
  3335. IN CTELockHandle LockHandleConn
  3336. )
  3337. /*++
  3338. Routine Description:
  3339. Arguments:
  3340. Return Value:
  3341. --*/
  3342. {
  3343. PNDIS_PACKET pPkt;
  3344. PSPX_SEND_RESD pSendResd;
  3345. USHORT startSeqNum;
  3346. BOOLEAN fLockHeld = TRUE, fDone = FALSE;
  3347. pSendResd = pSpxConnFile->scf_SendSeqListHead;
  3348. if (pSendResd)
  3349. {
  3350. startSeqNum = pSendResd->sr_SeqNum;
  3351. DBGPRINT(SEND, DBG,
  3352. ("spxConnResendPkts: StartSeqNum %lx for resend on %lx\n",
  3353. startSeqNum, pSpxConnFile));
  3354. while (spxConnGetPktBySeqNum(pSpxConnFile, startSeqNum++, &pPkt))
  3355. {
  3356. CTEAssert(pPkt != NULL);
  3357. pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
  3358. if (!(pSendResd->sr_State & SPX_SENDPKT_IPXOWNS))
  3359. {
  3360. DBGPRINT(SEND, DBG,
  3361. ("spxConnResendPkts: Pkt %lx.%lx resent on %lx\n",
  3362. pPkt, (startSeqNum - 1), pSpxConnFile));
  3363. // We are going to send this packet
  3364. pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
  3365. SPX_SENDPKT_REXMIT);
  3366. }
  3367. else
  3368. {
  3369. DBGPRINT(SEND, DBG,
  3370. ("spxConnResendPkts: Pkt %lx.%lx owned by ipx on %lx\n",
  3371. pPkt, (startSeqNum - 1), pSpxConnFile));
  3372. break;
  3373. }
  3374. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  3375. fLockHeld = FALSE;
  3376. // If pkt has the ack bit set, we break.
  3377. fDone = ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) != 0);
  3378. // Send the packet
  3379. SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
  3380. if (fDone)
  3381. {
  3382. break;
  3383. }
  3384. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  3385. fLockHeld = TRUE;
  3386. }
  3387. }
  3388. if (fLockHeld)
  3389. {
  3390. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  3391. }
  3392. return;
  3393. }
  3394. #endif