summaryrefslogblamecommitdiffstats
path: root/private/ntos/tdi/isnp/spx/spxsend.c
blob: 6b856953d30c2550275f9608e4afdffedd414a51 (plain) (tree)





































































































































































































































































                                                                                                            
/*++

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