You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
7.0 KiB
263 lines
7.0 KiB
/*++
|
|
|
|
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
|
|
|
|
|
|
|
|
|