diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isn/spx/spxsend.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/spx/spxsend.c b/private/ntos/tdi/isn/spx/spxsend.c new file mode 100644 index 000000000..6b856953d --- /dev/null +++ b/private/ntos/tdi/isn/spx/spxsend.c @@ -0,0 +1,262 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + spxsend.c + +Abstract: + + This module contains code that implements the send engine for the + SPX transport provider. + +Author: + + Nikhil Kamkolkar (nikhilk) 11-November-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "precomp.h" +#pragma hdrstop + + +// Define module number for event logging entries +#define FILENUM SPXSEND + +VOID +SpxSendComplete( + IN PNDIS_PACKET pNdisPkt, + IN NDIS_STATUS NdisStatus + ) + +/*++ + +Routine Description: + + This routine is called by the I/O system to indicate that a connection- + oriented packet has been shipped and is no longer needed by the Physical + Provider. + +Arguments: + + ProtocolBindingContext - The ADAPTER structure for this binding. + + NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent. + + NdisStatus - the completion status of the send. + +Return Value: + + none. + +--*/ + +{ + PSPX_CONN_FILE pSpxConnFile; + PSPX_SEND_RESD pSendResd; + PNDIS_BUFFER pNdisBuffer; + CTELockHandle lockHandle; + UINT bufCount; + PREQUEST pRequest = NULL; + BOOLEAN completeReq = FALSE, freePkt = FALSE, + orphaned = FALSE, lockHeld = FALSE; + + pSendResd = (PSPX_SEND_RESD)(pNdisPkt->ProtocolReserved); + +#if DBG + if (NdisStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(SEND, DBG, + ("SpxSendComplete: For %lx with status **%lx**\n", + pNdisPkt, NdisStatus)); + } +#endif + + // IPX changes the length set for the first ndis buffer descriptor. + // Change it back to its original value here. + NdisQueryPacket(pNdisPkt, NULL, &bufCount, &pNdisBuffer, NULL); + NdisAdjustBufferLength(pNdisBuffer, IpxMacHdrNeeded + MIN_IPXSPX2_HDRSIZE); + + do + { + pSpxConnFile = pSendResd->sr_ConnFile; + CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle); + lockHeld = TRUE; +#if defined(__PNP) + // + // if IPX gave us a new LocalTarget, use for our next send. + // + // But if we are sending connect requests by iterating over NicIds, + // dont update the local target bcoz that will screw up our iteration + // logic. + // + if ( DEVICE_NETWORK_PATH_NOT_FOUND == NdisStatus + && + !( + SPX_CONN_CONNECTING(pSpxConnFile) && + (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) && + (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) + ) ) { + + pSpxConnFile->scf_LocalTarget = pSendResd->LocalTarget; + + // + // Renegotiate the max packet size if we have an active SPX2 + // session going on and we negotiated the max size originally. + // + if ( SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE && + SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2) && + SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG) ) { + + // + // this call will get the local max size on this new local target + // from IPX. + // + SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr ); + SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG); + + DBGPRINT(SEND, DBG3, + ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n", + pSpxConnFile)); + } + + } +#endif __PNP + + CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0); + + // IPX dont own this packet nomore. + pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS; + + // If a send packet has been aborted, then we need to call + // abort send to go ahead and free up this packet, and deref associated + // request, if there is one, potentially completing it. + if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) != 0) + { + spxConnAbortSendPkt( + pSpxConnFile, + pSendResd, + SPX_CALL_TDILEVEL, + lockHandle); + + lockHeld = FALSE; + break; + } + + // If there is an associated request, remove reference on it. BUT for a + // sequenced packet only if it has been acked and is waiting for the request + // to be dereferenced. It is already dequeued from queue, just free it up. + if ((((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0) && + ((pSendResd->sr_State & SPX_SENDPKT_SEQ) == 0)) || + ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0)) + { + freePkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0); + + pRequest = pSendResd->sr_Request; + CTEAssert(pRequest != NULL); + + DBGPRINT(SEND, DBG, + ("IpxSendComplete: ReqRef before dec %lx.%lx\n", + pRequest, REQUEST_INFORMATION(pRequest))); + + // Deref the request and see if we complete it now. We always have our + // own reference on the request. + // !!! Status should already have been set in request...!!! + if (--(REQUEST_INFORMATION(pRequest)) == 0) + { + CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING); + + completeReq = TRUE; + + // If this is acked already, request is not on list. + // BUG #11626 + if ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) == 0) + { + RemoveEntryList(REQUEST_LINKAGE(pRequest)); + } + } + } + + // Do we destroy this packet? + if ((pSendResd->sr_State & SPX_SENDPKT_DESTROY) != 0) + { + // Remove this packet from the send list in the connection. + DBGPRINT(SEND, INFO, + ("IpxSendComplete: destroy packet...\n")); + + SpxConnDequeueSendPktLock(pSpxConnFile, pNdisPkt); + freePkt = TRUE; + } + + } while (FALSE); + + if (lockHeld) + { + CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle); + } + + if (freePkt) + { + DBGPRINT(SEND, INFO, + ("IpxSendComplete: free packet...\n")); + + SpxPktSendRelease(pNdisPkt); + } + + if (completeReq) + { + // If this is a send request, set info to data sent, else it will be + // zero. + if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_SEND) + { + PTDI_REQUEST_KERNEL_SEND pParam; + + pParam = (PTDI_REQUEST_KERNEL_SEND) + REQUEST_PARAMETERS(pRequest); + + REQUEST_INFORMATION(pRequest) = pParam->SendLength; + DBGPRINT(SEND, DBG, + ("IpxSendComplete: complete req %lx.%lx...\n", + REQUEST_STATUS(pRequest), + REQUEST_INFORMATION(pRequest))); + + CTEAssert(pRequest != NULL); + CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING); + SpxCompleteRequest(pRequest); + } + else + { + DBGPRINT(SEND, DBG, + ("SpxSendComplete: %lx DISC Request %lx with %lx.%lx\n", + pSpxConnFile, pRequest, REQUEST_STATUS(pRequest), + REQUEST_INFORMATION(pRequest))); + + DBGPRINT(SEND, DBG, + ("SpxSendComplete: %lx.%lx.%lx\n", + pSpxConnFile->scf_RefCount, + pSpxConnFile->scf_Flags, + pSpxConnFile->scf_Flags2)); + + // Set the request in the connection, and deref for it. + InsertTailList( + &pSpxConnFile->scf_DiscLinkage, + REQUEST_LINKAGE(pRequest)); + } + + SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY); + } + + return; + +} // SpxSendComplete + + + |