263 lines
6.7 KiB
C
263 lines
6.7 KiB
C
/*++
|
||
|
||
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 mess 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
|
||
|
||
|
||
|
||
|