summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/spx/spxcpkt.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isn/spx/spxcpkt.c')
-rw-r--r--private/ntos/tdi/isn/spx/spxcpkt.c4131
1 files changed, 4131 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/spx/spxcpkt.c b/private/ntos/tdi/isn/spx/spxcpkt.c
new file mode 100644
index 000000000..0c606ab0a
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxcpkt.c
@@ -0,0 +1,4131 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcpkt.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXCPKT
+
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ BOOLEAN fNeg, fSpx2;
+ TA_IPX_ADDRESS srcIpxAddr;
+ PTDI_IND_CONNECT connHandler;
+ USHORT srcConnId, destConnId, destSkt,
+ pktLen, seqNum, ackNum, allocNum;
+ PVOID connHandlerCtx;
+ PREQUEST pListenReq;
+ PSPX_SEND_RESD pSendResd;
+ NTSTATUS status;
+ CTELockHandle lockHandle, lockHandleDev, lockHandleConn;
+ CONNECTION_CONTEXT connCtx;
+ PIRP acceptIrp;
+ PSPX_ADDR pSpxAddr;
+ PSPX_ADDR_FILE pSpxAddrFile, pSpxRefFile;
+ PSPX_CONN_FILE pSpxConnFile;
+ PNDIS_PACKET pCrAckPkt;
+ BOOLEAN connectAccepted = FALSE, delayAccept = FALSE,
+ addrLock = FALSE, tdiListen = FALSE;
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // Verify Connect Request
+ if (((pIpxSpxHdr->hdr_ConnCtrl & (SPX_CC_ACK | SPX_CC_SYS)) !=
+ (SPX_CC_ACK | SPX_CC_SYS)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId != 0xFFFF))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifyCR Failed %lx.%lx\n",
+ srcConnId, destConnId));
+ return;
+ }
+
+ // Get the destination socket from the header
+ destSkt = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_DestSkt;
+
+ SpxBuildTdiAddress(
+ &srcIpxAddr,
+ sizeof(srcIpxAddr),
+ (PBYTE)pIpxSpxHdr->hdr_SrcNet,
+ pIpxSpxHdr->hdr_SrcNode,
+ pIpxSpxHdr->hdr_SrcSkt);
+
+ // Ok, get the address object this is destined for.
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ pSpxAddr = SpxAddrLookup(SpxDevice, destSkt);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ if (pSpxAddr == NULL)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceive: No addr for %lx\n", destSkt));
+
+ return;
+ }
+
+ fSpx2 = ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2));
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Received connect req! %d.%d\n",
+ fSpx2, fNeg));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+
+ // We use a bit setting in the flag to prevent reentering
+ // per address file.
+ //
+ // We first search the list of non-inactive connections on the address
+ // this packet came in on to see if it is a duplicate. If it is, we just
+ // resend ack. Note we dont need to scan the global connection list.
+ status = SpxAddrConnByRemoteIdAddrLock(
+ pSpxAddr, srcConnId, pIpxSpxHdr->hdr_SrcNet, &pSpxConnFile);
+
+ if (NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Received duplicate connect req! %lx\n",
+ pSpxConnFile));
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile) ||
+ (SPX_CONN_LISTENING(pSpxConnFile) &&
+ ((SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK) ||
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Sending Duplicate CR - ACK! %lx\n",
+ pSpxConnFile));
+
+ // Build and send an ack
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2));
+
+ if (pCrAckPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ // Send the CR Ack packet!
+ if (pCrAckPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+ }
+ }
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // We should return in this if, else addrLock should be set to
+ // FALSE.
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+ }
+
+ do
+ {
+ // New connection request:
+ // Assume we will be able to accept it and allocate a packet for the ack.
+ // Walk list of listening connections if any.
+
+ pSpxRefFile = NULL;
+ if ((pSpxConnFile = pSpxAddr->sa_ListenConnList) != NULL)
+ {
+ PTDI_REQUEST_KERNEL_LISTEN pParam;
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnIndicate: Listen available!\n"));
+
+ // dequeue connection
+ pSpxAddr->sa_ListenConnList = pSpxConnFile->scf_Next;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ pListenReq = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ pParam = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(pListenReq);
+
+ // if autoaccept, acceptIrp = listenIrp, get connection id and
+ // process as we do for an indication. As the connection has a
+ // listen posted on it, it must have a reference for it.
+ //
+ // if !autoaccept, we need to complete the listen irp.
+ delayAccept = (BOOLEAN)((pParam->RequestFlags & TDI_QUERY_ACCEPT) != 0);
+ if (delayAccept)
+ {
+ // Remove the listen irp and prepare for completion.
+ // NOTE!! Here we do not remove the listen reference. This will
+ // be removed if disconnect happens, or if accept
+ // happens, it is transferred to being ref for connection
+ // being active.
+ RemoveEntryList(REQUEST_LINKAGE(pListenReq));
+ REQUEST_STATUS(pListenReq) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pListenReq) = 0;
+ }
+
+ // Are we ok with spx2?
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2)) ||
+ !fSpx2)
+ {
+ // We better use spx only.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ fSpx2 = fNeg = FALSE;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ connectAccepted = TRUE;
+ tdiListen = TRUE;
+ }
+ else
+ {
+ // No listens available. Check for connect handlers.
+ // Walk list of address files indicating to each until accepted.
+ for (pSpxAddrFile = pSpxAddr->sa_AddrFileList;
+ pSpxAddrFile != NULL;
+ pSpxAddrFile = pSpxAddrFile->saf_Next)
+ {
+ if ((pSpxAddrFile->saf_Flags & (SPX_ADDRFILE_CLOSING |
+ SPX_ADDRFILE_CONNIND)) ||
+ ((connHandler = pSpxAddrFile->saf_ConnHandler) == NULL))
+ {
+ continue;
+ }
+
+ // Connect indication in progress, drop all subsequent.
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_CONNIND;
+
+ connHandlerCtx = pSpxAddrFile->saf_ConnHandlerCtx;
+ SpxAddrFileLockReference(pSpxAddrFile, AFREF_INDICATION);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ // Make the indication. We are always returned an accept irp on
+ // indication. Else we fail to accept the connection.
+ status = (*connHandler)(
+ connHandlerCtx,
+ sizeof(srcIpxAddr),
+ (PVOID)&srcIpxAddr,
+ 0, // User data length
+ NULL, // User data
+ 0, // Option length
+ NULL, // Options
+ &connCtx,
+ &acceptIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConn: indicate status %lx.%lx\n",
+ status, acceptIrp));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_CONNIND;
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ CTEAssert(acceptIrp != NULL);
+
+ // Find the connection and accept the connection using that
+ // connection object.
+ SpxConnFileReferenceByCtxLock(
+ pSpxAddrFile,
+ connCtx,
+ &pSpxConnFile,
+ &status);
+
+ if (!NT_SUCCESS(status))
+ {
+ // The connection object is closing, or is not found
+ // in our list. The accept irp must have had the same
+ // connection object. AFD isnt behaving well.
+ KeBugCheck(0);
+ }
+
+ // Only for debugging.
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_BYCTX,
+ CFREF_VERIFY);
+
+ pListenReq = SpxAllocateRequest(
+ SpxDevice,
+ acceptIrp);
+
+ IF_NOT_ALLOCATED(pListenReq)
+ {
+ acceptIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ break;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pListenReq));
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ connectAccepted = TRUE;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((pSpxAddrFile->saf_Flags & SPX_ADDRFILE_SPX2) && fSpx2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+ else
+ {
+ fSpx2 = fNeg = FALSE;
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+
+ break;
+ }
+ else
+ {
+ // We are not going to accept the connection on this address.
+ // Try next one.
+ pSpxRefFile = pSpxAddrFile;
+ continue;
+ }
+ }
+ }
+
+ } while (FALSE);
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // No need for flag from this point on.
+ // addrLock = FALSE;
+ }
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ if (connectAccepted)
+ {
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_LocalConnId = spxConnGetId();
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RetrySeqNum = 0;
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleConnReq: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Set max packet size in connection
+ SPX_MAX_PKT_SIZE(pSpxConnFile, (fSpx2 && fNeg), fSpx2, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Accept connect req on %lx.%lx..%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ // Aborts must now deal with the lists. Need this as Accept has to
+ // deal with it.
+ // Put in non-inactive list. All processing now is equivalent to
+ // that when a listen is completed on a connection.
+ if ((!tdiListen) && (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile))))
+ {
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile);
+
+ // Insert in the global connection tree on device.
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fNeg ? SPX_CONNFILE_NEG : 0) |
+ (fSpx2 ? SPX_CONNFILE_SPX2: 0)));
+
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+#if 0
+ //
+ // Make sure that this connection got a local disconnect if it was an SPXI
+ // connection earlier, in response to a TDI_DISCONNECT_RELEASE.
+ //
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX] == 0);
+#endif
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, (delayAccept ? SPX_LISTEN_RECDREQ : 0));
+
+ if (!delayAccept)
+ {
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandle,
+ lockHandleConn);
+ }
+ else
+ {
+ // Release the locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ // Complete the listen irp. Note reference is not removed. Done when
+ // accept is posted.
+ SpxCompleteRequest(pListenReq);
+ }
+ } else {
+ ++SpxDevice->dev_Stat.NoListenFailures;
+ }
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the client side of the connection.
+ Handles:
+ Session Negotiate
+ Sends Session Setup, when recd, handles SS Ack
+
+ STATE MACHINE:
+
+ RR
+ / \
+ / \ ReceivedAck(SPX1Connection)
+ / \
+ / \--------> ACTIVE
+ / ^
+ Send / |
+ ACK / |
+ / |
+ / RecvNeg/NoNeg |
+ / SendSS |
+ SA--------->SS---------------+
+ ^ | SSAckRecv
+ | |
+ +-----+
+ RecvNeg
+
+ RR - Received Connect Request
+ SA - Sent CR Ack
+ SS - Sent Session Setup
+
+ We move from SA to SS when connection is not negotiatiable and we
+ immediately send the SS, or when we receive negotiate packet and send the neg
+ ack and the session setup.
+
+ Note we could receive a negotiate packet when in SS, as our ack to the
+ negotiate could have been dropped. We deal with this.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PNDIS_PACKET pSnAckPkt, pSsPkt = NULL;
+ PSPX_SEND_RESD pSendResd, pSsSendResd;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN locksHeld = FALSE;
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromClient: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_RECDREQ:
+
+ // Do nothing.
+ break;
+
+ case SPX_LISTEN_SETUP:
+
+ // Is this a setup ack? If so, yippee. Our ack to a negotiate packet
+ // could have been dropped, and so we could also get a negotiate packet
+ // in that case. If that happens, fall through.
+ // Verify Ss Ack
+ if (!SPX2_CONN(pSpxConnFile) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: VerifySSACK Failed Checking SN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ // Fall through to see if this is a neg packet
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG)))
+ {
+ break;
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Recd SSACK %lx\n",
+ pSpxConnFile));
+
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ case SPX_LISTEN_SENTACK:
+
+ // We expect a negotiate packet.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify Sn
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySN Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ CTEAssert(negSize > 0);
+
+ // Build sn ack, abort if we fail
+ SpxPktBuildSnAck(
+ pSpxConnFile,
+ &pSnAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY);
+
+ if (pSnAckPkt == NULL)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SNACK %lx\n",
+ pSpxConnFile));
+
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnAckPkt);
+
+ // The session packet should already be on queue.
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pSsPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SS %lx\n",
+ pSpxConnFile));
+
+ pSsSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+
+ // We need to resend the packet
+ if ((pSsSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ pSsPkt = NULL;
+ }
+ else
+ {
+ // Set the size to the neg size indicated in connection.
+ // This could be lower than the size the packet was build
+ // with originally. But will never be higher.
+ pSsSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ spxConnSetNegSize(
+ pSsPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+ }
+
+ // If we are actually LISTEN_SETUP, then send the ss packet also.
+ // We need to start the connect timer to resend the ss pkt.
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ SPX_LISTEN_SETSTATE(pSpxConnFile, SPX_LISTEN_SETUP);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSnAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnAckPkt, pSendResd);
+
+ // If we have to send the session setup packet, send that too.
+ if (pSsPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the server side of the connection. This will both
+ release the lock and dereference the connection as it sees fit.
+
+ STATE MACHINE:
+
+ SR--CTimerExpires-->IDLE
+ /| \
+ / | \ ReceivedAck(SPX1Connection)
+ / | \
+ / | \--------> ACTIVE
+ (Neg) / | ^
+ Send / |RecvAck |
+ SN / |NoNeg |
+ / | |
+ / | |
+ / v |
+ SN--------->WS---------------+
+ RecvSNAck RecvSS
+
+ SR - Sent Connect request
+ SN - Sent Session Negotiate
+ WS - Waiting for session setup packet
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN fNeg, fSpx2;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN cTimerCancelled = FALSE, fAbort = FALSE, locksHeld = FALSE;
+ PNDIS_PACKET pSsAckPkt, pSnPkt, pPkt = NULL;
+
+ // We should get a CR Ack, or if our substate is sent session neg
+ // we should get a session neg ack, or if we are waiting for session
+ // setup, we should get one of those.
+
+ fSpx2 = (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2);
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // Check if this qualifies as the ack.
+ // Verify CR Ack
+ if ((pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ ((pktLen != MIN_IPXSPX_HDRSIZE) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen != MIN_IPXSPX2_HDRSIZE))) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleSessPktFromSrv: CRAck Invalid %lx %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pktLen, negSize, pIpxSpxHdr->hdr_ConnCtrl));
+
+ break;
+ }
+
+ // !!!BUGBUG!!!
+ // From current spx code base:
+ // Do we need to send an ack to this ack? In case of SPX only?
+ // What if this ack is dropped? We need to send an ack, if in future
+ // we get CONNECT REQ Acks, until we reach active?
+ // * If they want an ack schedule it. The normal case is for this not
+ // * to happen, but some Novell mainframe front ends insist on having
+ // * this. And technically, it is OK for them to do this.
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: Recd CRACK %lx\n", pSpxConnFile));
+
+ // Grab the remote alloc num/conn id (in net format)
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ // If we have been looking for network 0, which means the
+ // packets were sent on all NIC IDs, update our local
+ // target now that we have received a response.
+
+#if defined(_PNP_POWER)
+ if (pSpxConnFile->scf_LocalTarget.NicHandle.NicId == (USHORT)ITERATIVE_NIC_ID) {
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#endif _PNP_POWER
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ if (!fSpx2 || !fNeg)
+ {
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference transferred to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // Set max packet size, assume not spx2 or !neg, so pass in FALSE
+ SPX_MAX_PKT_SIZE(pSpxConnFile, FALSE, FALSE, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPSrv: Accept connect req on %lx.%lx.%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ if (!fSpx2)
+ {
+ // Reset spx2 flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+
+ // Complete connect request, this free the lock.
+ // Cancels tdi timer too. Sets all necessary flags.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ if (!fNeg)
+ {
+ // Goto W_SETUP
+ // Reset all connect related flags, also spx2/neg flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ break;
+ }
+
+ // Reset max packet size. SPX2 and NEG.
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, pIpxSpxHdr->hdr_SrcNet);
+
+ CTEAssert(negSize > 0);
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ pSpxConnFile->scf_MaxPktSize =
+ MIN(negSize, pSpxConnFile->scf_MaxPktSize);
+
+ pSpxConnFile->scf_MaxPktSize = (USHORT)
+ MIN(pSpxConnFile->scf_MaxPktSize, PARAM(CONFIG_MAX_PACKET_SIZE));
+
+ // For SPX2 with negotiation, we set up sneg packet and move to
+ // SPX_CONNECT_NEG.
+ SpxPktBuildSn(
+ pSpxConnFile,
+ &pSnPkt,
+ SPX_SENDPKT_IPXOWNS);
+
+ if (pSnPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Queue in packet
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnPkt);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SN %lx\n",
+ pSpxConnFile));
+
+ // Reset retry count for connect timer
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Change state.
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_NEG);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send the packet
+ pSendResd = (PSPX_SEND_RESD)(pSnPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnPkt, pSendResd);
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ // We expect a session neg ack.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify SN Ack
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySNACK Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SNACK %lx %lx.%lx\n",
+ pSpxConnFile, negSize, pSpxConnFile->scf_MaxPktSize));
+
+ if (negSize > pSpxConnFile->scf_MaxPktSize)
+ negSize = pSpxConnFile->scf_MaxPktSize;
+
+ // Get the size to use
+ if (negSize <= pSpxConnFile->scf_MaxPktSize)
+ {
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ else
+ {
+ // Free the negotiate packet
+ SpxPktSendRelease(pPkt);
+ }
+
+ CTEAssert(pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER);
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ // Start the watchdog timer, if fail, we abort.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ // Complete cr with error.
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference goes to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ // We move to the W_SETUP state.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ }
+
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+
+ // Does this qualify as a session setup packet?
+ // Verify SS
+ if (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySS Failed %lx.%lx, %lx %lx.%lx\n",
+ srcConnId, destConnId, negSize,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SS %lx\n", pSpxConnFile));
+
+ // Copy remote address over into connection (socket could change)
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+
+ // Build ss ack, abort if we fail
+ SpxPktBuildSsAck(
+ pSpxConnFile,
+ &pSsAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT);
+
+ if (pSsAckPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SSACK %lx\n",
+ pSpxConnFile));
+
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+
+ // We dont queue in the pkt as its already marked as abort.
+ // Queue in the packet.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pSsAckPkt);
+
+ // Complete connect, this releases lock.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSsAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsAckPkt, pSendResd);
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (fAbort)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (cTimerCancelled)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine abort a connection (both client and server side) in the middle
+ of a connection establishment.
+
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest = NULL;
+ int numDerefs = 0;
+
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ KeBugCheck(0);
+ }
+#endif
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) { // others should be counted elsewhere
+ ++SpxDevice->dev_Stat.LocalResourceFailures;
+ }
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel all timers
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+
+ // We could be called from disconnect for an accept in which case there
+ // will be no queued request. But we need to remove the reference if there
+ // is no request (an accept/listen irp) and listen state is on.
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // Save req in conn for deref to complete.
+ pSpxConnFile->scf_ConnectReq = pRequest;
+
+ numDerefs++;
+ }
+ else if (SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ numDerefs++;
+ }
+
+ // Bug #20999
+ // Race condition was an abort came in from timer, but the connect state
+ // was left unchanged. Due to an extra ref on the connection from the
+ // aborted cr, the state remained so, and then the cr ack came in, and
+ // a session neg was built and queued on the connection. Although it should
+ // not have been. And we hit the assert in deref where the connection is
+ // being reinitialized. Since this can be called for both listening and
+ // connecting connections, do the below.
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine completes a connection (both client and server side)
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCompleteConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ DBGBRK(FATAL);
+ }
+#endif
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel tdi connect timer if we are connecting.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (pSpxConnFile->scf_CRetryCount == (LONG)(PARAM(CONFIG_CONNECTION_COUNT))) {
+ ++SpxDevice->dev_Stat.ConnectionsAfterNoRetry;
+ } else {
+ ++SpxDevice->dev_Stat.ConnectionsAfterRetry;
+ }
+
+ // Reset all connect related flags
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER)
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_ACTIVE);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_IDLE);
+
+ ++SpxDevice->dev_Stat.OpenConnections;
+
+ // Initialize timer values
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = PARAM(CONFIG_INITIAL_RETRANSMIT_TIMEOUT);
+ pSpxConnFile->scf_DevT1 = 0;
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // When we complete the request, we essentially transfer the reference
+ // to the fact that the connection is active. This will be taken away
+ // when a Disconnect happens on the connection and we transition from
+ // ACTIVE to DISCONN.
+ // numDerefs++;
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ // Complete request
+ SpxCompleteRequest(pRequest);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+{
+ PNDIS_PACKET pSsPkt, pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+
+ BOOLEAN fNeg = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAcceptCr: %lx.%d.%d\n",
+ pSpxConnFile, fSpx2, fNeg));
+
+ // Build and queue in packet.
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ fNeg,
+ fSpx2);
+
+ if ((pCrAckPkt != NULL) &&
+ (pSpxConnFile->scf_LocalConnId != 0))
+ {
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // Start the timer
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // We start the connect timer for retrying ss which we send out now
+ // if we are not negotiating.
+ if (fSpx2)
+ {
+ // Build the session setup packet also for spx2.
+ SpxPktBuildSs(
+ pSpxConnFile,
+ &pSsPkt,
+ (USHORT)(fNeg ? 0 : SPX_SENDPKT_IPXOWNS));
+
+ if (pSsPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pSsPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+ if (!fNeg)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+ }
+ }
+
+ CTEAssert((fNeg && fSpx2) || (!fSpx2 && !fNeg));
+
+ // For a SPX connection, we immediately become active. This happens
+ // in the completeConnect routine. !!Dont change it here!!
+ if (!fSpx2)
+ {
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+ }
+ else
+ {
+ SPX_LISTEN_SETSTATE(
+ pSpxConnFile, (fNeg ? SPX_LISTEN_SENTACK : SPX_LISTEN_SETUP));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+ }
+
+ // Send the CR Ack packet!
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+
+ if (fSpx2 && !fNeg)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ return(TRUE);
+
+
+AbortConnect:
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+
+ return (FALSE);
+}
+
+
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ The caller needs to set the state to packetize before calling this
+ routine. This can be called when SEND state is RENEG also.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+ fNormalState - If true, it will assume it can release lock to send,
+ else, it just builds pkts without releasing lock and
+ releases lock at end. Used after reneg changes size.
+
+Return Value:
+
+
+--*/
+{
+ PLIST_ENTRY p;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT windowSize;
+ ULONG dataLen;
+ USHORT sendFlags;
+ int numDerefs = 0;
+ BOOLEAN fFirstPass = TRUE, fSuccess = TRUE;
+ PREQUEST pRequest;
+
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ fNormalState)
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ // Build all of the packets. The firsttime flag is used so
+ // that if we get a 0 byte send, we will send it. The firsttime
+ // flag will be set and we will build the packet and send it.
+ //
+ // FOR SPX1, we cannot trust the remote window size. So we only send
+ // stuff if window size is greater than 0 *AND* we do not have any pending
+ // sends. Dont get in here if we are ABORT. Dont want to be handling any
+ // more requests.
+ while((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ABORT) &&
+ ((pRequest = pSpxConnFile->scf_ReqPkt) != NULL) &&
+ ((pSpxConnFile->scf_ReqPktSize > 0) || fFirstPass))
+ {
+ fFirstPass = FALSE;
+ windowSize = pSpxConnFile->scf_RecdAllocNum -
+ pSpxConnFile->scf_SendSeqNum + 1;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: WINDOW %lx for %lx\n",
+ windowSize, pSpxConnFile));
+
+
+ DBGPRINT(SEND, DBG,
+ ("REMALLOC %lx SENDSEQ %lx\n",
+ pSpxConnFile->scf_RecdAllocNum,
+ pSpxConnFile->scf_SendSeqNum));
+
+
+ CTEAssert(windowSize >= 0);
+
+ // Disconnect/Orderly release is not subject to window closure.
+ if ((pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA) &&
+ (((windowSize == 0) && SPX2_CONN(pSpxConnFile)) ||
+ (!SPX2_CONN(pSpxConnFile) &&
+ (pSpxConnFile->scf_SendSeqListHead != NULL))))
+ {
+ break;
+ }
+
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA)
+ {
+ CTEAssert(pRequest == pSpxConnFile->scf_ReqPkt);
+
+ // Get data length
+ dataLen = (ULONG)MIN(pSpxConnFile->scf_ReqPktSize,
+ (pSpxConnFile->scf_MaxPktSize -
+ ((SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE))));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: %lx Sending %lx Size %lx Req %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ dataLen,
+ pSpxConnFile->scf_ReqPkt,
+ pSpxConnFile->scf_ReqPktSize));
+
+ // Build data packet. Handles 0-length for data. Puts in seq num in
+ // send resd section of packet also.
+ sendFlags =
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) |
+ SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ |
+ ((!SPX2_CONN(pSpxConnFile) || (windowSize == 1)) ?
+ SPX_SENDPKT_ACKREQ : 0));
+
+ if (dataLen == pSpxConnFile->scf_ReqPktSize)
+ {
+ // Last packet of send, ask for a ack.
+ sendFlags |= (SPX_SENDPKT_LASTPKT | SPX_SENDPKT_ACKREQ);
+ if ((pSpxConnFile->scf_ReqPktFlags & TDI_SEND_PARTIAL) == 0)
+ sendFlags |= SPX_SENDPKT_EOM;
+ }
+
+ SpxPktBuildData(
+ pSpxConnFile,
+ &pPkt,
+ sendFlags,
+ (USHORT)dataLen);
+ }
+ else
+ {
+ dataLen = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("Building DISC packet on %lx ReqPktSize %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_ReqPktSize));
+
+ // Build informed disc/orderly rel packet, associate with request
+ SpxPktBuildDisc(
+ pSpxConnFile,
+ pRequest,
+ &pPkt,
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) | SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ | SPX_SENDPKT_LASTPKT),
+ (UCHAR)((pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL) ?
+ SPX2_DT_ORDREL : SPX2_DT_IDISC));
+ }
+
+ if (pPkt != NULL)
+ {
+ // If we were waiting to send an ack, we don't have to as we are
+ // piggybacking it now. Cancel ack timer, get out.
+ if (fNormalState && SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Piggyback happening for %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // We are sending data, allow piggybacks to happen.
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_ATimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ }
+
+ if (pSpxConnFile->scf_ReqPktType != SPX_REQ_DATA)
+ {
+ // For a disconnect set the state
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ numDerefs++;
+ }
+ else if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_ORDREL)
+ {
+ CTEAssert((SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_ACTIVE) ||
+ (SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_DISCONN));
+
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ }
+ else
+ {
+ CTEAssert(
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL));
+ }
+ }
+ else
+ {
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+ CTEAssert(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC);
+
+ // Note we have send the idisc here.
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_IDISC);
+ }
+ }
+ }
+ else
+ {
+ fSuccess = FALSE;
+ break;
+ }
+
+
+ // Queue in packet, reference request for the packet
+ SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt);
+ REQUEST_INFORMATION(pRequest)++;
+
+ pSpxConnFile->scf_ReqPktSize -= dataLen;
+ pSpxConnFile->scf_ReqPktOffset += dataLen;
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx Size after pkt %lx.%lx\n",
+ pSpxConnFile->scf_ReqPkt, pSpxConnFile->scf_ReqPktSize,
+ dataLen));
+
+ // Even if window size if zero, setup next request is current one
+ // is done. We are here only after we have packetized this send req.
+ if (pSpxConnFile->scf_ReqPktSize == 0)
+ {
+ // This request has been fully packetized. Either go on to
+ // next request or we are done packetizing.
+ p = REQUEST_LINKAGE(pRequest);
+ if (p->Flink == &pSpxConnFile->scf_ReqLinkage)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx done, no more\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pRequest = NULL;
+ }
+ else
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p->Flink);
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Req done, setting next %lx.%lx\n",
+ pRequest, pParam->SendLength));
+
+ DBGPRINT(SEND, INFO,
+ ("-%lx-\n",
+ pRequest));
+
+ // Set parameters in connection for another go.
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if ((pSpxConnFile->scf_ReqPktSize = pParam->SendLength) == 0)
+ {
+ // Another zero length send.
+ fFirstPass = TRUE;
+ }
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ fFirstPass = TRUE;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+ }
+ }
+
+ if (fNormalState)
+ {
+ // Send the packet if we are not at the reneg state
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ ++SpxDevice->dev_Stat.DataFramesSent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesSent,
+ dataLen);
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if retry timer needs to be started.
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)))
+ {
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnPacketize: Failed to start retry timer\n"));
+
+ fSuccess = FALSE;
+ break;
+ }
+ }
+ }
+
+ // Dont overwrite an error state.
+ if (((fNormalState) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3) &&
+ (pSpxConnFile->scf_SendSeqListHead == NULL)))
+ {
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, ERR,
+ ("COULD NOT PACKETIZE AFTER RENEG %lx\n", pSpxConnFile));
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(fSuccess);
+}
+
+
+
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_RECEIVE pParam;
+ NTSTATUS status = STATUS_PENDING;
+
+ if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ pParam = (PTDI_REQUEST_KERNEL_RECEIVE)REQUEST_PARAMETERS(pRequest);
+ pSpxConnFile->scf_CurRecvReq = pRequest;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = pParam->ReceiveLength;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnQueueRecv: %lx.%lx\n", pRequest, pParam->ReceiveLength));
+
+ // Reference connection for this recv.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ InsertTailList(
+ &pSpxConnFile->scf_RecvLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // RECV irps have no creation references.
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+
+ // State to receive_posted if we are idle.
+ if (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_POSTED);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+{
+ CTELockHandle lockHandleInter;
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+
+ InitializeListHead(&ReqList);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnCompletePended: PENDING RECV REQUESTS IN DONE LIST! %lx\n",
+ pSpxConnFile));
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ p = pSpxConnFile->scf_RecvDoneLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+
+#if DBG
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_RECEIVE)
+ {
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ // If we are not already in ack queue, queue ourselves in starting
+ // ack timer.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // First start ack timer.
+ if ((pSpxConnFile->scf_ATimerId =
+ SpxTimerScheduleEvent(
+ spxConnAckTimer,
+ 100,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ ++SpxDevice->dev_Stat.PiggybackAckQueued;
+ }
+ }
+
+ return;
+}
+
+
+
+
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendAck: ACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an ack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendNack: NACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an nack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ TRUE,
+ NumToSend);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle interLockHandle;
+ USHORT seqNum = 0, ackNum;
+ int numDerefs = 0;
+ BOOLEAN fLastPkt, lockHeld = TRUE, fAbort = FALSE,
+ fResetRetryTimer, fResendPkt = FALSE, fResetSendQueue = FALSE;
+
+ if (pIpxSpxHdr != NULL)
+ {
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ // Ack numbers should already be set in connection!
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRYWD:
+
+ // Did we receive an ack for pending data? If so, we goto
+ // idle and process the ack.
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RETRYWD %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+ else
+ {
+ // Ok, we received an ack for our probe retry, goto
+ // renegotiate packet size.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ }
+
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // We better have a data packet in the list.
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead);
+
+#if DBG
+ if ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx.%lx.%lx RENEGACK SEQNUM %lx ACKNUM %lx EXPSEQ %lx\n",
+ pSpxConnFile,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT),
+ seqNum,
+ ackNum,
+ (pSpxConnFile->scf_SendSeqListHead->sr_SeqNum + 1)));
+ }
+#endif
+
+ // Verify we received an RR ack. If so, we set state to
+ // SEND_RETRY3. First repacketize if we need to.
+ if ((SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT)) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG! NEW %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ // Dont allow anymore reneg packet acks to be looked at.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Also set the new send sequence number.
+ pSpxConnFile->scf_SendSeqNum =
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1);
+
+ // Get the max packet size we will really use. Retry timer
+ // could have sent other sizes by now, so we can't depend
+ // on whats set.
+ // Remember max packet size in connection.
+ GETSHORT2SHORT(
+ &pSpxConnFile->scf_MaxPktSize, &pIpxSpxHdr->hdr_NegSize);
+
+ // Basic sanity checking on the max packet size.
+ if (pSpxConnFile->scf_MaxPktSize < SPX_NEG_MIN)
+ pSpxConnFile->scf_MaxPktSize = SPX_NEG_MIN;
+
+ // Get ready to reset the send queue.
+ fResetSendQueue = TRUE;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG DONE : RETRY3 %lx.%lx MP %lx!\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: DUPLICATE RENEG ACK %lx!\n",
+ pSpxConnFile));
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Data acked %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+#if DBG
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: CONN RESTORED %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+ }
+#endif
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Ok, we received an ack for our watchdog. Done.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ break;
+
+ default:
+
+ break;
+ }
+
+#if DBG
+ if (seqNum != 0)
+ {
+ // We have a nack, which contains an implicit ack.
+ // Instead of nack processing, what we do is we resend a
+ // packet left unacked after ack processing. ONLY if we
+ // either enter the loop below (fResetRetryTimer is FALSE)
+ // or if seqNum is non-zero (SPX2 only NACK)
+ }
+#endif
+ }
+ }
+
+ // Once our numbers are updated, we check to see if any of our packets
+ // have been acked.
+ fResetRetryTimer = TRUE;
+ while (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) ||
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE) ||
+ fResetSendQueue) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ // Reset retry timer
+ if (fResetRetryTimer)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_RTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ }
+
+ fResetRetryTimer = FALSE;
+ }
+
+ // Update the retry seq num.
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pRequest = pSendResd->sr_Request;
+
+#if DBG
+ if (fResetSendQueue)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RENEG %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(SEND, DBG,
+ ("%lx Acked\n", pSendResd->sr_SeqNum));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: %lx Seq %lx Acked Sr %lx Req %lx %lx.%lx\n",
+ pSpxConnFile,
+ pSendResd->sr_SeqNum,
+ pSendResd,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // If this packet is the last one comprising this request, remove request
+ // from queue. Calculate retry time.
+ fLastPkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_LASTPKT) != 0);
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_REXMIT) == 0) &&
+ ((pSendResd->sr_SeqNum + 1) == pSpxConnFile->scf_RecdAckNum))
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ // This is the packet which is being acked. Adjust round trip
+ // timer.
+ li = pSendResd->sr_SentTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new time
+ SpxCalculateNewT1(pSpxConnFile, value);
+ }
+ }
+
+ if (fLastPkt)
+ {
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Remove creation reference
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: LASTSEQ # %lx for Req %lx with %lx.%lx\n",
+ pSendResd->sr_SeqNum,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ }
+
+ // Dequeue the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0);
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Dereference request for the dequeing of the packet
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Packet owned by IPX. What do we do now? Set acked pkt so request
+ // gets dereferenced in send completion. Note that the packet is already
+ // off the queue and is floating at this point.
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: IPXOWNS Pkt %lx with %lx.%lx\n",
+ pPkt, pRequest, REQUEST_STATUS(pRequest)));
+
+ pSendResd->sr_State |= SPX_SENDPKT_ACKEDPKT;
+ }
+
+ if (SPX2_CONN(pSpxConnFile) &&
+ (REQUEST_MINOR_FUNCTION(pRequest) == TDI_DISCONNECT) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL))
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ORDREL_ACKED);
+
+ // If we had received an ordrel in the meantime, we need
+ // to disconnect.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ fAbort = TRUE;
+ }
+ }
+
+ // All packets comprising a request have been acked!
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ CTELockHandle lockHandleInter;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+
+ }
+ }
+#if DBG
+ else if (fLastPkt)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: ReqFloating %lx.%lx\n",
+ pSpxConnFile, pRequest));
+ }
+#endif
+ }
+
+ // See if we reset the send queue and repacketize.
+ if (fResetSendQueue)
+ {
+ // Reset send queue and repacketize only if pkts left unacked.
+ if (pSpxConnFile->scf_SendSeqListHead)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resetting send queue %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ spxConnResetSendQueue(pSpxConnFile);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Repacketizing %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SpxConnPacketize(pSpxConnFile, FALSE, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+ else
+ {
+ // We just go back to idle state now.
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: All packets acked reneg ack! %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+ }
+ }
+
+ // See if we resend a packet.
+ if ((seqNum != 0) &&
+ !fAbort &&
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0))
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ }
+
+ // Push into packetize only if we received an ack. And if there arent any
+ // packets already waiting. Probably retransmit happening.
+ if (!fAbort &&
+ SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_ReqPkt != NULL) &&
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_PKTQ)) &&
+ ((pSpxConnFile->scf_SendSeqListHead) == NULL) &&
+ (!SPX2_CONN(pSpxConnFile) ||
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL))))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: Recd ack pktizng\n", pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_PKTIZE);
+
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ else if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ USHORT seqNum, ackNum, allocNum, maxPktSize;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ // The remote sent us a renegotiate request. We need to send an ack back
+ // ONLY if we have not acked a data packet with that same sequence number.
+ // This is guaranteed by the fact that we will not accept the reneg request
+ // if we have already acked a data packet with the same seq num, as our
+ // receive seq number would be incremented already.
+ //
+ // Note that if we have pending send packets we may end up doing a reneg
+ // also.
+
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&maxPktSize, &pIpxSpxHdr->hdr_PktLen);
+
+ // If the received seq num is less than the expected receive sequence number
+ // we ignore this request.
+ if (!UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ (seqNum != pSpxConnFile->scf_RecvSeqNum))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx ERROR RENSEQ %lx RECVSEQ %lx %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ return;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RENSEQ %lx RECVSEQ %lx MAXPKT %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum, maxPktSize));
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ // Set RenegAckAckNum before calling buildrrack. If a previous reneg
+ // request was received with a greater maxpktsize, send an ack with
+ // that maxpktsize.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD))
+ {
+ pSpxConnFile->scf_RenegAckAckNum = pSpxConnFile->scf_RecvSeqNum;
+ pSpxConnFile->scf_RenegMaxPktSize= maxPktSize;
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Adjust sentallocnum now that recvseqnum might have moved up.
+ pSpxConnFile->scf_SentAllocNum +=
+ (seqNum - pSpxConnFile->scf_RenegAckAckNum);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM ADJUSTED %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+ }
+
+ // The recvseqnum for the reneg is always >= the renegackacknum.
+ pSpxConnFile->scf_RecvSeqNum = seqNum;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RESET RECVSEQ %lx SavedACKACK %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum));
+
+ // Build and send an ack.
+ SpxPktBuildRrAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ pSpxConnFile->scf_RenegMaxPktSize);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+#if DBG
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendRenegReqAck: Could not allocate!\n"));
+ }
+#endif
+
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ int numDerefs = 0;
+ PNDIS_PACKET pPkt = NULL;
+ BOOLEAN lockHeld = TRUE, fAbort = FALSE;
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ORDREL_ACKED)
+ {
+ fAbort = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this pkt
+ // Update seq numbers and stuff.
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for this. Ordinary spx2 ack.
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // Get disconnect handler if we have one. And have not indicated
+ // abortive disconnect on this connection to afd.
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler =pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx=pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ // We abort any receives here if !fAbort else we abort conn.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ }
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for the idisc. Need to modify data type
+ // and reset sys bit on ack.
+ // BUG #12344 - Fixing this led to the problem where we queue in
+ // the pkt below, but AbortSends could already have been called
+ // => this packet stays on queue without a ref, conn gets freed
+ // underneath, and in the sendcomplete we crash when this send
+ // completes.
+ //
+ // Fix is to setup this pkt as a aborted pkt to start with.
+
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ pSendHdr->hdr_ConnCtrl &= ~SPX_CC_SYS;
+ pSendHdr->hdr_DataType = SPX2_DT_IDISC_ACK;
+
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // We better not have any received pkts, we ignore disconnect
+ // pkts when that happens.
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+#if DBG
+ if (pSpxConnFile->scf_SendSeqListHead != NULL)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA/DISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+ }
+#endif
+
+ // Call abortive disconnect on connection.
+
+ //
+ // [SA] bug #15249
+ // This is an informed disconnect, hence pass DISCONNECT_RELEASE to AFD (TRUE in last param)
+ //
+ //
+ // We pass true only in the case of an SPX connection. SPX2 connections follow the
+ // exact semantics of Informed Disconnect.
+ //
+ if (!SPX2_CONN(pSpxConnFile)) {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ TRUE);
+ } else {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ CTEAssert(pSendResd != NULL);
+
+ pRequest = pSendResd->sr_Request;
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = pSendResd->sr_Request;
+ pSpxConnFile->scf_ReqPktOffset = pSendResd->sr_Offset;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset SEND Req to %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest, pParam->SendLength));
+
+ // Set parameters in connection for another go. Size parameter is
+ // original size - offset at this point.
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength -
+ pSpxConnFile->scf_ReqPktOffset;
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset DISC Req to %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest));
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: Seq Num for %lx is now %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_SendSeqNum));
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ do
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ KeBugCheck(0);
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ } while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Called to abort either a sequenced or a non-sequenced packet ONLY from
+ send completion.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0)
+ {
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ // BUG #11626 - request is already removed from list.
+ // RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ABORTPKT);
+
+ if (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ // First go through the non-seq pkt queue.Just set abort flag if owned by ipx
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) == 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt if its not already.
+ // We only do this check for the non-sequenced packets.
+ // BUG #12344 (see SpxRecvDiscPacket())
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) == 0)
+ {
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+ }
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+ // If retry timer state is on, then we need to reset and deref.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ DBGPRINT(SEND, DBG1,
+ ("spxConnAbortSends: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // Remove creation references on all sends.
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ p = pSpxConnFile->scf_ReqLinkage.Flink;
+ while (p != &pSpxConnFile->scf_ReqLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on. Its complete or abort list for it.
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Aborting Send Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PBYTE pData;
+ ULONG dataLen;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ // Reset the current receive request values
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ // If we have any buffered data, abort it.
+ // Buffered data that is 0 bytes long (only eom) may not have a ndis
+ // buffer associated with it.
+ while ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL)
+ {
+ if ((pSpxConnFile->scf_RecvListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pSpxConnFile->scf_RecvListTail = NULL;
+ }
+
+ pNdisPkt = (PNDIS_PACKET)
+ CONTAINING_RECORD(pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("spxConnAbortRecvs: %lx in bufferlist on %lx\n",
+ pSpxConnFile, pNdisPkt));
+
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ SpxFreeMemory(pData);
+ NdisFreeBuffer(pNdisBuffer);
+ }
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ // Free the ndis packet
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ // If packets are on this queue, they are waiting for transfer data to
+ // complete. Can't do much about that, just go and remove creation refs
+ // on the receives.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ p = pSpxConnFile->scf_RecvLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("SpxRecvAbort: Aborting Recv Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ numDerefs++;
+
+ SpxCompleteRequest(pRequest);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+#if 0
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT startSeqNum;
+ BOOLEAN fLockHeld = TRUE, fDone = FALSE;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ if (pSendResd)
+ {
+ startSeqNum = pSendResd->sr_SeqNum;
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: StartSeqNum %lx for resend on %lx\n",
+ startSeqNum, pSpxConnFile));
+
+ while (spxConnGetPktBySeqNum(pSpxConnFile, startSeqNum++, &pPkt))
+ {
+ CTEAssert(pPkt != NULL);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if (!(pSendResd->sr_State & SPX_SENDPKT_IPXOWNS))
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx resent on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+
+ // We are going to send this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_REXMIT);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx owned by ipx on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+ break;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ fLockHeld = FALSE;
+
+ // If pkt has the ack bit set, we break.
+ fDone = ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) != 0);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ if (fDone)
+ {
+ break;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fLockHeld = TRUE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return;
+}
+#endif