1489 lines
29 KiB
C
1489 lines
29 KiB
C
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
aspc.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the ASP client protocol.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (jameelh@microsoft.com)
|
|
Nikhil Kamkolkar (nikhilk@microsoft.com)
|
|
|
|
Revision History:
|
|
30 Mar 1993 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#include <atalk.h>
|
|
#pragma hdrstop
|
|
#define FILENUM ASPC
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, AtalkInitAspCInitialize)
|
|
#pragma alloc_text(PAGE, AtalkAspCCreateAddress)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCCleanupAddress)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCCloseAddress)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCCreateConnection)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCCleanupConnection)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCCloseConnection)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCAssociateAddress)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCDissociateAddress)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCPostConnect)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCDisconnect)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCGetStatus)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCGetAttn)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCCmdOrWrite)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCIncomingOpenReply)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCIncomingStatus)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCIncomingCmdReply)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCHandler)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCAddrDereference)
|
|
#pragma alloc_text(PAGEASPC, AtalkAspCConnDereference)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCSessionMaintenanceTimer)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCQueueAddrGlobalList)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCDeQueueAddrGlobalList)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCQueueConnGlobalList)
|
|
#pragma alloc_text(PAGEASPC, atalkAspCDeQueueConnGlobalList)
|
|
#endif
|
|
|
|
VOID
|
|
AtalkInitAspCInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
AtalkTimerInitialize(&atalkAspCConnMaint.ascm_SMTTimer,
|
|
atalkAspCSessionMaintenanceTimer,
|
|
ASP_SESSION_MAINTENANCE_TIMER);
|
|
INITIALIZE_SPIN_LOCK(&atalkAspCLock);
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCreateAddress(
|
|
IN PATALK_DEV_CTX pDevCtx OPTIONAL,
|
|
OUT PASPC_ADDROBJ * ppAspAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an ASP address object.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR Status;
|
|
PASPC_ADDROBJ pAspAddr;
|
|
int i;
|
|
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
|
("AtalkAspCCreateAddr: Entered\n"));
|
|
|
|
// Allocate memory for the Asp address object
|
|
*ppAspAddr = NULL;
|
|
if ((pAspAddr = AtalkAllocZeroedMemory(sizeof(ASPC_ADDROBJ))) == NULL)
|
|
{
|
|
return ATALK_RESR_MEM;
|
|
}
|
|
|
|
// Create an Atp Socket on the port for the Sls
|
|
Status = AtalkAtpOpenAddress(AtalkDefaultPort,
|
|
0,
|
|
NULL,
|
|
ATP_DEF_MAX_SINGLE_PKT_SIZE,
|
|
ATP_DEF_SEND_USER_BYTES_ALL,
|
|
NULL,
|
|
FALSE,
|
|
&pAspAddr->aspcao_pAtpAddr);
|
|
|
|
if (!ATALK_SUCCESS(Status))
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("AtalkAspCCreateAddress: AtalkAtpOpenAddress %ld\n", Status));
|
|
AtalkFreeMemory(pAspAddr);
|
|
return Status;
|
|
}
|
|
|
|
// Initialize the Asp address object
|
|
#if DBG
|
|
pAspAddr->aspcao_Signature = ASPCAO_SIGNATURE;
|
|
#endif
|
|
INITIALIZE_SPIN_LOCK(&pAspAddr->aspcao_Lock);
|
|
|
|
atalkAspCQueueAddrGlobalList(pAspAddr);
|
|
|
|
// Refcount for creation and atp address. This goes away when atp address is closed
|
|
// pAspAddr->aspcao_Flags = 0;
|
|
pAspAddr->aspcao_RefCount = 1 + 1;
|
|
*ppAspAddr = pAspAddr;
|
|
|
|
return ATALK_NO_ERROR;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCleanupAddress(
|
|
IN PASPC_ADDROBJ pAspAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return(ATALK_NO_ERROR);
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCloseAddress(
|
|
IN PASPC_ADDROBJ pAspAddr,
|
|
IN GENERIC_COMPLETION CompletionRoutine,
|
|
IN PVOID CloseContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return(ATALK_NO_ERROR);
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCreateConnection(
|
|
IN PVOID pConnCtx, // Context to associate with the session
|
|
IN PATALK_DEV_CTX pDevCtx OPTIONAL,
|
|
OUT PASPC_CONNOBJ * ppAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an ASP session. The created session starts off being an orphan, i.e.
|
|
it has no parent address object. It gets one when it is associated.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PASPC_CONNOBJ pAspConn;
|
|
|
|
// Allocate memory for a connection object
|
|
if ((pAspConn = AtalkAllocZeroedMemory(sizeof(ASPC_CONNOBJ))) == NULL)
|
|
{
|
|
return ATALK_RESR_MEM;
|
|
}
|
|
|
|
#if DBG
|
|
pAspConn->aspcco_Signature = ASPCCO_SIGNATURE;
|
|
#endif
|
|
|
|
INITIALIZE_SPIN_LOCK(&pAspConn->aspcco_Lock);
|
|
pAspConn->aspcco_ConnCtx = pConnCtx;
|
|
// pAspConn->aspcco_Flags = 0;
|
|
pAspConn->aspcco_RefCount = 1; // Creation reference
|
|
pAspConn->aspcco_NextSeqNum = 1; // Set to 1, not 0.
|
|
AtalkInitializeRT(&pAspConn->aspcco_RT,
|
|
ASP_INIT_REQ_INTERVAL,
|
|
ASP_MIN_REQ_INTERVAL,
|
|
ASP_MAX_REQ_INTERVAL);
|
|
|
|
*ppAspConn = pAspConn;
|
|
|
|
// Insert into the global connection list.
|
|
atalkAspCQueueConnGlobalList(pAspConn);
|
|
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
|
("AtalkAspCreateConnection: %lx\n", pAspConn));
|
|
|
|
return ATALK_NO_ERROR;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCleanupConnection(
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return ATALK_NO_ERROR;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCloseConnection(
|
|
IN PASPC_CONNOBJ pAspConn,
|
|
IN GENERIC_COMPLETION CompletionRoutine,
|
|
IN PVOID CloseContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return ATALK_NO_ERROR;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCAssociateAddress(
|
|
IN PASPC_ADDROBJ pAspAddr,
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR error;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT(VALID_ASPCAO(pAspAddr));
|
|
ASSERT(VALID_ASPCCO(pAspConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
|
|
error = ATALK_ALREADY_ASSOCIATED;
|
|
if ((pAspConn->aspcco_Flags & ASPCCO_ASSOCIATED) == 0)
|
|
{
|
|
error = ATALK_NO_ERROR;
|
|
|
|
pAspConn->aspcco_Flags |= ASPCCO_ASSOCIATED;
|
|
pAspConn->aspcco_pAspCAddr = pAspAddr;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCDissociateAddress(
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PASPC_ADDROBJ pAspAddr;
|
|
KIRQL OldIrql;
|
|
ATALK_ERROR error = ATALK_NO_ERROR;
|
|
|
|
ASSERT(VALID_ASPCCO(pAspConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
if ((pAspConn->aspcco_Flags & (ASPCCO_CONNECTING |
|
|
ASPCCO_ACTIVE |
|
|
ASPCCO_ASSOCIATED)) != ASPCCO_ASSOCIATED)
|
|
{
|
|
error = ATALK_INVALID_CONNECTION;
|
|
}
|
|
else
|
|
{
|
|
pAspAddr = pAspConn->aspcco_pAspCAddr ;
|
|
ASSERT(VALID_ASPCAO(pAspAddr));
|
|
|
|
// Clear associated flag.
|
|
pAspConn->aspcco_Flags &= ~ASPCCO_ASSOCIATED;
|
|
pAspConn->aspcco_pAspCAddr = NULL;
|
|
}
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCPostConnect(
|
|
IN PASPC_CONNOBJ pAspConn,
|
|
IN PATALK_ADDR pRemoteAddr,
|
|
IN PVOID pConnectCtx,
|
|
IN GENERIC_COMPLETION CompletionRoutine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR error = ATALK_NO_ERROR;
|
|
BOOLEAN DerefConn = FALSE;
|
|
KIRQL OldIrql;
|
|
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
|
PBYTE pOpenPkt = NULL, pRespPkt = NULL;
|
|
PAMDL pOpenAmdl = NULL, pRespAmdl = NULL;
|
|
PASPC_ADDROBJ pAspAddr = pAspConn->aspcco_pAspCAddr;
|
|
|
|
ASSERT(VALID_ASPCAO(pAspAddr));
|
|
ASSERT(VALID_ASPCCO(pAspConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
|
|
do
|
|
{
|
|
if ((pAspConn->aspcco_Flags & (ASPCCO_CONNECTING |
|
|
ASPCCO_ACTIVE |
|
|
ASPCCO_ASSOCIATED)) != ASPCCO_ASSOCIATED)
|
|
{
|
|
error = ATALK_INVALID_CONNECTION;
|
|
break;
|
|
}
|
|
|
|
// Reference the connection for the request we will be posting
|
|
AtalkAspCConnReferenceByPtrNonInterlock(pAspConn, &error);
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
DerefConn = TRUE;
|
|
|
|
// Make sure flags are clean.
|
|
pAspConn->aspcco_Flags |= ASPCCO_CONNECTING;
|
|
pAspConn->aspcco_ConnectCtx = pConnectCtx;
|
|
pAspConn->aspcco_ConnectCompletion = CompletionRoutine;
|
|
pAspConn->aspcco_ServerSlsAddr = *pRemoteAddr;
|
|
|
|
// Copy the atp address object for efficiency
|
|
pAspConn->aspcco_pAtpAddr = pAspAddr->aspcao_pAtpAddr;
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG("AtalkAspCPostConnect: Connection ref failed\n", 0);
|
|
}
|
|
} while (FALSE);
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
UserBytes[ASP_CMD_OFF] = ASP_OPEN_SESSION;
|
|
UserBytes[ASP_WSS_OFF] = pAspAddr->aspcao_pAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Socket;
|
|
UserBytes[ASP_VERSION_OFF] = ASP_VERSION[0];
|
|
UserBytes[ASP_VERSION_OFF+1] = ASP_VERSION[1];
|
|
|
|
// Post the open session request.
|
|
error = AtalkAtpPostReq(pAspConn->aspcco_pAtpAddr,
|
|
&pAspConn->aspcco_ServerSlsAddr,
|
|
&pAspConn->aspcco_OpenSessTid,
|
|
ATP_REQ_EXACTLY_ONCE, // ExactlyOnce request
|
|
NULL,
|
|
0,
|
|
UserBytes,
|
|
NULL,
|
|
0,
|
|
ATP_RETRIES_FOR_ASP,
|
|
ATP_MAX_INTERVAL_FOR_ASP,
|
|
THIRTY_SEC_TIMER,
|
|
atalkAspCIncomingOpenReply,
|
|
pAspConn);
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
error = ATALK_PENDING;
|
|
DerefConn = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("AtalkAspCPostConnect: AtalkAtpPostReq: failed %ld\n", error));
|
|
|
|
// Remove connection from the connect list and reset states.
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
|
|
pAspConn->aspcco_Flags &= ~ASPCCO_CONNECTING;
|
|
pAspConn->aspcco_ConnectCtx = NULL;
|
|
pAspConn->aspcco_ConnectCompletion = NULL;
|
|
pAspConn->aspcco_pAtpAddr = NULL;
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("AtalkAspCPostConnect: failed %ld\n", error));
|
|
}
|
|
}
|
|
|
|
if (DerefConn)
|
|
{
|
|
AtalkAspCConnDereference(pAspConn);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCDisconnect(
|
|
IN PASPC_CONNOBJ pAspConn,
|
|
IN ATALK_DISCONNECT_TYPE DisconnectType,
|
|
IN PVOID pDisconnectCtx,
|
|
IN GENERIC_COMPLETION CompletionRoutine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PASPC_REQUEST pAspReq, pAspReqNext;
|
|
KIRQL OldIrql;
|
|
ATALK_ERROR Error;
|
|
|
|
// Abort all pending requests.
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
|
|
pAspConn->aspcco_Flags |= ASPCCO_DISCONNECTING;
|
|
for (pAspReq = pAspConn->aspcco_pActiveReqs;
|
|
pAspReq = pAspReq->aspcrq_Next;
|
|
pAspReq = pAspReqNext)
|
|
{
|
|
pAspReqNext = pAspReq->aspcrq_Next;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
// Send a close session request to the other end
|
|
// Error = AtalKAtpPostReq(pAspConn->aspcco_ServerSlsAddr);
|
|
|
|
return ATALK_NO_ERROR;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCGetStatus(
|
|
IN PASPC_ADDROBJ pAspAddr,
|
|
IN PATALK_ADDR pRemoteAddr,
|
|
IN PAMDL pStatusAmdl,
|
|
IN USHORT AmdlSize,
|
|
IN PACTREQ pActReq
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR error;
|
|
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
|
USHORT tid;
|
|
|
|
if ((pRemoteAddr->ata_Network == 0) ||
|
|
(pRemoteAddr->ata_Node == 0) ||
|
|
(pRemoteAddr->ata_Socket == 0))
|
|
{
|
|
return ATALK_SOCKET_INVALID;
|
|
}
|
|
|
|
*(DWORD *)UserBytes = 0;
|
|
UserBytes[ASP_CMD_OFF] = ASP_GET_STATUS;
|
|
|
|
error = AtalkAtpPostReq(pAspAddr->aspcao_pAtpAddr,
|
|
pRemoteAddr,
|
|
&tid,
|
|
0, // ExactlyOnce request
|
|
NULL,
|
|
0,
|
|
UserBytes,
|
|
pStatusAmdl,
|
|
AmdlSize,
|
|
ATP_RETRIES_FOR_ASP,
|
|
ATP_MAX_INTERVAL_FOR_ASP,
|
|
THIRTY_SEC_TIMER,
|
|
atalkAspCIncomingStatus,
|
|
(PVOID)pActReq);
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
error = ATALK_PENDING;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCGetAttn(
|
|
IN PASPC_CONNOBJ pAspConn,
|
|
IN PAMDL pReadBuf,
|
|
IN USHORT ReadBufLen,
|
|
IN ULONG ReadFlags,
|
|
IN PVOID pReadCtx,
|
|
IN GENERIC_READ_COMPLETION CompletionRoutine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR error = ATALK_NO_ERROR;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT(VALID_ASPCCO(pAspConn));
|
|
ASSERT(*CompletionRoutine != NULL);
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
|
|
do
|
|
{
|
|
if ((pAspConn->aspcco_Flags & ASPCCO_ACTIVE) == 0)
|
|
{
|
|
error = ATALK_ASPC_CONN_NOT_ACTIVE;
|
|
break;
|
|
}
|
|
|
|
if ((ReadFlags & TDI_RECEIVE_EXPEDITED) == 0)
|
|
{
|
|
error = ATALK_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (pAspConn->aspcco_Flags & ASPCCO_ATTN_PENDING)
|
|
{
|
|
error = ATALK_ASPC_TOO_MANY_READS;
|
|
break;
|
|
}
|
|
|
|
// PEEK not supported for ASPC
|
|
if (ReadFlags & TDI_RECEIVE_PEEK)
|
|
{
|
|
error = ATALK_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
|
|
// We should have space for atleast one attention word
|
|
if (ReadBufLen < sizeof(USHORT))
|
|
{
|
|
error = ATALK_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
// Check if we have any outstanding attention words
|
|
if (pAspConn->aspcco_AttnOutPtr < pAspConn->aspcco_AttnInPtr)
|
|
{
|
|
PUSHORT AttnBuf;
|
|
USHORT BufSize = 0;
|
|
|
|
AttnBuf = AtalkGetAddressFromMdlSafe(
|
|
pReadBuf,
|
|
NormalPagePriority);
|
|
if (AttnBuf == NULL) {
|
|
error = ATALK_FAILURE;
|
|
break;
|
|
}
|
|
while (pAspConn->aspcco_AttnOutPtr < pAspConn->aspcco_AttnInPtr)
|
|
{
|
|
*AttnBuf++ = pAspConn->aspcco_AttnBuf[pAspConn->aspcco_AttnOutPtr % MAX_ASPC_ATTNS];
|
|
pAspConn->aspcco_AttnOutPtr++;
|
|
BufSize += sizeof(USHORT);
|
|
}
|
|
(*CompletionRoutine)(error,
|
|
pReadBuf,
|
|
BufSize,
|
|
ReadFlags,
|
|
pReadCtx);
|
|
|
|
error = ATALK_PENDING;
|
|
break;
|
|
}
|
|
error = ATALK_INVALID_CONNECTION;
|
|
if ((pAspConn->aspcco_Flags & (ASPCCO_CLOSING | ASPCCO_DISCONNECTING)) == 0)
|
|
{
|
|
AtalkAspCConnReferenceByPtrNonInterlock(pAspConn, &error);
|
|
}
|
|
|
|
if (!ATALK_SUCCESS(error))
|
|
{
|
|
break;
|
|
}
|
|
|
|
pAspConn->aspcco_Flags |= ASPCCO_ATTN_PENDING;
|
|
|
|
// Remember read information in the connection object.
|
|
pAspConn->aspcco_ReadCompletion = CompletionRoutine;
|
|
pAspConn->aspcco_ReadCtx = pReadCtx;
|
|
|
|
} while (FALSE);
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkAspCCmdOrWrite(
|
|
IN PASPC_CONNOBJ pAspConn,
|
|
IN PAMDL pCmdMdl,
|
|
IN USHORT CmdSize,
|
|
IN PAMDL pReplyMdl,
|
|
IN USHORT ReplySize,
|
|
IN BOOLEAN fWrite, // If TRUE, its a write else command
|
|
IN PACTREQ pActReq
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
Reply and Write buffers are overlaid.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR Error;
|
|
KIRQL OldIrql;
|
|
PASPC_REQUEST pAspReq;
|
|
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
|
|
|
do
|
|
{
|
|
if (((pAspConn->aspcco_Flags & (ASPCCO_ACTIVE |
|
|
ASPCCO_CONNECTING |
|
|
ASPCCO_LOCAL_CLOSE |
|
|
ASPCCO_REMOTE_CLOSE |
|
|
ASPCCO_CLOSING)) != ASPCCO_ACTIVE))
|
|
{
|
|
Error = ATALK_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
|
|
AtalkAspCConnReference(pAspConn, &Error);
|
|
if (!ATALK_SUCCESS(Error))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ((pAspReq = (PASPC_REQUEST)AtalkAllocZeroedMemory(sizeof(ASPC_REQUEST))) == NULL)
|
|
{
|
|
Error = ATALK_RESR_MEM;
|
|
break;
|
|
}
|
|
#if DBG
|
|
pAspReq->aspcrq_Signature = ASPCRQ_SIGNATURE;
|
|
#endif
|
|
pAspReq->aspcrq_Flags = fWrite ? ASPCRQ_WRITE : ASPCRQ_COMMAND;
|
|
pAspReq->aspcrq_pReplyMdl = pReplyMdl;
|
|
pAspReq->aspcrq_ReplySize = ReplySize;
|
|
pAspReq->aspcrq_RefCount = 2; // Creation+incoming reply handler
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
|
|
pAspReq->aspcrq_SeqNum = pAspConn->aspcco_NextSeqNum ++;
|
|
pAspReq->aspcrq_Next = pAspConn->aspcco_pActiveReqs;
|
|
pAspConn->aspcco_pActiveReqs = pAspReq;
|
|
pAspReq->aspcrq_pAspConn = pAspConn;
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
// Build user bytes and send our request over
|
|
UserBytes[ASP_CMD_OFF] = fWrite ? ASP_CMD : ASP_WRITE;
|
|
UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspcco_SessionId;
|
|
PUTSHORT2SHORT(&UserBytes[ASP_SEQUENCE_NUM_OFF], pAspReq->aspcrq_SeqNum);
|
|
|
|
Error = AtalkAtpPostReq(pAspConn->aspcco_pAtpAddr,
|
|
&pAspConn->aspcco_ServerSssAddr,
|
|
&pAspReq->aspcrq_ReqXactId,
|
|
ATP_REQ_EXACTLY_ONCE, // XO request
|
|
pCmdMdl,
|
|
CmdSize,
|
|
UserBytes,
|
|
pReplyMdl,
|
|
ReplySize,
|
|
ATP_RETRIES_FOR_ASP, // Retry count
|
|
pAspConn->aspcco_RT.rt_Base,// Retry interval
|
|
THIRTY_SEC_TIMER,
|
|
atalkAspCIncomingCmdReply,
|
|
pAspReq);
|
|
|
|
if (!ATALK_SUCCESS(Error))
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("AtalkAspCCmdOrWrite: AtalkAtpPostReq failed %lx\n", Error));
|
|
atalkAspCIncomingCmdReply(Error,
|
|
pAspReq,
|
|
pCmdMdl,
|
|
pReplyMdl,
|
|
ReplySize,
|
|
UserBytes);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
AtalkAspCConnectionIsValid(
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PASPC_CONNOBJ pTmpConn;
|
|
BOOLEAN fConnIsValid=FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&atalkAspCLock, &OldIrql);
|
|
|
|
pTmpConn = atalkAspCConnList;
|
|
|
|
while (pTmpConn)
|
|
{
|
|
if (pTmpConn == pAspConn)
|
|
{
|
|
fConnIsValid = TRUE;
|
|
break;
|
|
}
|
|
|
|
pTmpConn = pTmpConn->aspcco_Next;
|
|
}
|
|
RELEASE_SPIN_LOCK(&atalkAspCLock, OldIrql);
|
|
|
|
return(fConnIsValid);
|
|
}
|
|
|
|
LOCAL VOID
|
|
atalkAspCCloseSession(
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCIncomingOpenReply(
|
|
IN ATALK_ERROR ErrorCode,
|
|
IN PASPC_CONNOBJ pAspConn, // Our context
|
|
IN PAMDL pReqAmdl,
|
|
IN PAMDL pReadAmdl,
|
|
IN USHORT ReadLen,
|
|
IN PBYTE ReadUserBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ATALK_ERROR error;
|
|
USHORT OpenStatus;
|
|
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
|
BOOLEAN DerefConn = FALSE;
|
|
PASPC_ADDROBJ pAspAddr = pAspConn->aspcco_pAspCAddr;
|
|
|
|
ASSERT(VALID_ASPCCO(pAspConn));
|
|
|
|
if (ATALK_SUCCESS(ErrorCode))
|
|
do
|
|
{
|
|
// Check for open reply code in packet.
|
|
GETSHORT2SHORT(&OpenStatus, &ReadUserBytes[ASP_ERRORCODE_OFF]);
|
|
if (OpenStatus != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("atalkAspCIncomingOpenReply: Failed %ld, %lx\n", OpenStatus, pAspConn));
|
|
|
|
DerefConn = TRUE; // Since we are not queuing a request handler
|
|
ErrorCode = ATALK_REMOTE_CLOSE;
|
|
break;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
|
|
// Save the socket the server's SSS
|
|
pAspConn->aspcco_ServerSssAddr = pAspConn->aspcco_ServerSlsAddr;
|
|
pAspConn->aspcco_ServerSssAddr.ata_Socket = ReadUserBytes[ASP_SSS_OFF];
|
|
pAspConn->aspcco_SessionId = ReadUserBytes[ASP_SESSIONID_OFF];
|
|
pAspConn->aspcco_Flags &= ~ASPCCO_CONNECTING;
|
|
pAspConn->aspcco_Flags |= ASPCCO_ACTIVE;
|
|
|
|
pAspConn->aspcco_LastContactTime = AtalkGetCurrentTick();
|
|
|
|
// Reference for the request handler
|
|
AtalkAspCConnReferenceByPtrNonInterlock(pAspConn, &error);
|
|
|
|
// Build up userBytes to start tickling the other end.
|
|
UserBytes[ASP_CMD_OFF] = ASP_TICKLE;
|
|
UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspcco_SessionId;
|
|
PUTSHORT2SHORT(UserBytes + ASP_ERRORCODE_OFF, 0);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
|
|
// Set the request handler on this connection.
|
|
// It will handle tickle's, close's and write-continue
|
|
AtalkAtpSetReqHandler(pAspAddr->aspcao_pAtpAddr,
|
|
atalkAspCHandler,
|
|
pAspConn);
|
|
|
|
error = AtalkAtpPostReq(pAspConn->aspcco_pAtpAddr,
|
|
&pAspConn->aspcco_ServerSlsAddr,
|
|
&pAspConn->aspcco_TickleTid,
|
|
0, // ALO transaction
|
|
NULL,
|
|
0,
|
|
UserBytes,
|
|
NULL,
|
|
0,
|
|
ATP_INFINITE_RETRIES,
|
|
ASP_TICKLE_INTERVAL,
|
|
THIRTY_SEC_TIMER,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
pAspConn->aspcco_Flags |= ASPCCO_TICKLING;
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
}
|
|
else
|
|
{
|
|
DerefConn = TRUE; // Since we are not queuing a request handler
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (!ATALK_SUCCESS(ErrorCode))
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("atalkAspCIncomingOpenReply: Incoming connect fail %lx\n", ErrorCode));
|
|
|
|
AtalkAspCConnDereference(pAspConn);
|
|
|
|
// Mark it as inactive
|
|
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
pAspConn->aspcco_Flags &= ~ASPCCO_ACTIVE;
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
}
|
|
|
|
// Call the completion routine.
|
|
(*pAspConn->aspcco_ConnectCompletion)(ErrorCode, pAspConn->aspcco_ConnectCtx);
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCIncomingStatus(
|
|
IN ATALK_ERROR ErrorCode,
|
|
IN PACTREQ pActReq, // Our Ctx
|
|
IN PAMDL pReqAmdl,
|
|
IN PAMDL pStatusAmdl,
|
|
IN USHORT StatusLen,
|
|
IN PBYTE ReadUserBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
// Call the action completion routine
|
|
(*pActReq->ar_Completion)(ErrorCode, pActReq);
|
|
}
|
|
|
|
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCIncomingCmdReply(
|
|
IN ATALK_ERROR Error,
|
|
IN PASPC_REQUEST pAspReq,
|
|
IN PAMDL pReqAMdl,
|
|
IN PAMDL pRespAMdl,
|
|
IN USHORT RespSize,
|
|
IN PBYTE RespUserBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PASPC_CONNOBJ pAspConn;
|
|
PASPC_REQUEST * ppAspReq;
|
|
KIRQL OldIrql;
|
|
|
|
pAspConn = pAspReq->aspcrq_pAspConn;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
// Unlink the request from the active list
|
|
for (ppAspReq = &pAspConn->aspcco_pActiveReqs;
|
|
*ppAspReq != NULL;
|
|
ppAspReq = &((*ppAspReq)->aspcrq_Next))
|
|
{
|
|
if (pAspReq == *ppAspReq)
|
|
{
|
|
*ppAspReq = pAspReq->aspcrq_Next;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(*ppAspReq == pAspReq->aspcrq_Next);
|
|
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
// Complete the request
|
|
(*pAspReq->aspcrq_pActReq->ar_Completion)(Error, pAspReq->aspcrq_pActReq);
|
|
|
|
// and dereference the connection
|
|
AtalkAspCConnDereference(pAspConn);
|
|
|
|
// and finally free the request
|
|
AtalkFreeMemory(pAspReq);
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCHandler(
|
|
IN ATALK_ERROR ErrorCode,
|
|
IN PASPC_CONNOBJ pAspConn,
|
|
IN PATP_RESP pAtpResp, // Used by PostResp/CancelResp
|
|
IN PATALK_ADDR pSrcAddr, // Address of requestor
|
|
IN USHORT PktLen,
|
|
IN PBYTE pPkt,
|
|
IN PBYTE pUserBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Handle tickle, write-continue requests, attentions and close from the server.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
USHORT SequenceNum; // From the incoming packet
|
|
BYTE SessionId; // -- ditto --
|
|
BYTE RequestType; // -- ditto --
|
|
BOOLEAN CancelTickle, ReleaseLock = TRUE, CancelResp = FALSE, Deref = FALSE;
|
|
PIRP exRecvIrp;
|
|
PTDI_IND_RECEIVE_EXPEDITED exRecvHandler;
|
|
PVOID exRecvHandlerCtx;
|
|
ULONG exIndicateFlags;
|
|
PASPC_REQUEST pAspReq;
|
|
ATALK_ERROR Error;
|
|
|
|
do
|
|
{
|
|
if (!ATALK_SUCCESS(ErrorCode))
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("atalkAspCHandler: Error %ld\n", ErrorCode));
|
|
// Take away the reference on the Conn now that the atp address is closing
|
|
if (ErrorCode == ATALK_ATP_CLOSING)
|
|
AtalkAspCConnDereference(pAspConn);
|
|
break;
|
|
}
|
|
|
|
ASSERT(VALID_ASPCCO(pAspConn));
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
|
|
SessionId = pUserBytes[ASP_SESSIONID_OFF];
|
|
RequestType = pUserBytes[ASP_CMD_OFF];
|
|
GETSHORT2SHORT(&SequenceNum, pUserBytes+ASP_SEQUENCE_NUM_OFF);
|
|
|
|
AtalkAspCConnReferenceByPtrNonInterlock(pAspConn, &Error);
|
|
if (ATALK_SUCCESS(Error) && (pAspConn->aspcco_SessionId == SessionId))
|
|
{
|
|
pAspConn->aspcco_LastContactTime = AtalkGetCurrentTick();
|
|
|
|
switch (RequestType)
|
|
{
|
|
case ASP_CLOSE_SESSION:
|
|
// Cancel all outstanding requests (and any posted replies to write continue)
|
|
// and shut down the session. Start off by sending a close response.
|
|
CancelTickle = ((pAspConn->aspcco_Flags &ASPCO_TICKLING) != 0);
|
|
pAspConn->aspcco_Flags &= ~(ASPCCO_ACTIVE | ASPCCO_TICKLING);
|
|
pAspConn->aspcco_Flags |= ASPCO_REMOTE_CLOSE;
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
ReleaseLock = FALSE;
|
|
|
|
// Send a CloseSession reply and close the session
|
|
Error = AtalkAtpPostResp(pAtpResp,
|
|
pSrcAddr,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
AtalkAtpGenericRespComplete,
|
|
pAtpResp);
|
|
if (!ATALK_SUCCESS(Error))
|
|
{
|
|
AtalkAtpGenericRespComplete(Error, pAtpResp);
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("atalkAspSssXHandler: AtalkAtpPostResp failed %ld\n", Error));
|
|
}
|
|
|
|
// Cancel the tickle requests for this session
|
|
if (CancelTickle)
|
|
{
|
|
Error = AtalkAtpCancelReq(pAspConn->aspcco_pAtpAddr,
|
|
pAspConn->aspcco_TickleXactId,
|
|
&pAspConn->aspcco_ServerSssAddr);
|
|
|
|
if (!ATALK_SUCCESS(Error))
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("atalkAspSssXHandler: AtalkAtpCancelReq %ld\n", Error));
|
|
}
|
|
}
|
|
|
|
// Shut down this session, well almost ... Note that we have a reference
|
|
// to this connection which will be Dereferenced by atalkAspSessionClose.
|
|
atalkAspCCloseSession(pAspConn);
|
|
break;
|
|
|
|
case ASP_ATTENTION:
|
|
// Server is sending us an attention. If we already have a getattn posted
|
|
// complete that. If not, just save the attention word and indicate to AFD
|
|
// that we have recvd. expedited data
|
|
if ((pAspConn->aspcco_AttnInPtr - pAspConn->aspcco_AttnOutPtr) < MAX_ASPC_ATTNS)
|
|
{
|
|
pAspConn->aspcco_AttnBuf[pAspConn->aspcco_AttnInPtr % MAX_ASPC_ATTNS] = SequenceNum;
|
|
pAspConn->aspcco_AttnInPtr++;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
ReleaseLock = FALSE;
|
|
}
|
|
break;
|
|
|
|
case ASP_WRITE_DATA:
|
|
// We need to find the request for which we sent a Write command. The
|
|
// server now needs the data. Post a response for this.
|
|
for (pAspReq = pAspConn->aspcco_pActiveReqs;
|
|
pAspReq != NULL;
|
|
pAspReq = pAspReq->aspcrq_Next)
|
|
{
|
|
if (pAspReq->aspcrq_SeqNum == SequenceNum)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
ReleaseLock = FALSE;
|
|
Error = AtalkAtpPostResp(pAtpResp,
|
|
pSrcAddr,
|
|
pAspReq->aspcrq_pWriteMdl,
|
|
pAspReq->aspcrq_WriteSize,
|
|
NULL,
|
|
AtalkAtpGenericRespComplete,
|
|
pAtpResp);
|
|
Deref = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASP_TICKLE:
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
|
("atalkAspCHandler: Received tickle from %x.%x Session %d\n",
|
|
pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
|
CancelResp = TRUE;
|
|
Deref = TRUE;
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
|
("atalkAspCHandler: Invalid commnd %d from %x.%x Session %d\n",
|
|
RequestType, pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
|
CancelResp = TRUE;
|
|
Deref = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
|
("atalkAspCHandler: Mismatched session id from %d.%d, expected %d, recvd. %d\n",
|
|
pSrcAddr->ata_Network, pSrcAddr->ata_Node,
|
|
pAspConn->aspcco_SessionId, SessionId));
|
|
}
|
|
|
|
if (ReleaseLock)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspcco_Lock);
|
|
}
|
|
if (CancelResp)
|
|
{
|
|
AtalkAtpCancelResp(pAtpResp);
|
|
}
|
|
if (Deref)
|
|
{
|
|
AtalkAspCConnDereference(pAspConn);
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
|
|
|
|
LOCAL LONG FASTCALL
|
|
atalkAspCSessionMaintenanceTimer(
|
|
IN PTIMERLIST pTimer,
|
|
IN BOOLEAN TimerShuttingDown
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
return ATALK_TIMER_REQUEUE;
|
|
}
|
|
|
|
|
|
VOID FASTCALL
|
|
AtalkAspCAddrDereference(
|
|
IN PASPC_ADDROBJ pAspAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Close = FALSE;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_REFASPADDR,
|
|
("AtalkAspCAddrDereference: %lx, %d\n",
|
|
pAspAddr, pAspAddr->aspcao_RefCount-1));
|
|
|
|
ASSERT (VALID_ASPCAO(pAspAddr));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspAddr->aspcao_Lock, &OldIrql);
|
|
if (--(pAspAddr->aspcao_RefCount) == 0)
|
|
{
|
|
ASSERT(pAspAddr->aspcao_Flags & ASPCAO_CLOSING);
|
|
Close = TRUE;
|
|
}
|
|
RELEASE_SPIN_LOCK(&pAspAddr->aspcao_Lock, OldIrql);
|
|
|
|
if (Close)
|
|
{
|
|
if (pAspAddr->aspcao_CloseCompletion != NULL)
|
|
(*pAspAddr->aspcao_CloseCompletion)(ATALK_NO_ERROR,
|
|
pAspAddr->aspcao_CloseContext);
|
|
// Finally free the memory
|
|
AtalkFreeMemory(pAspAddr);
|
|
|
|
AtalkUnlockAspCIfNecessary();
|
|
}
|
|
}
|
|
|
|
|
|
VOID FASTCALL
|
|
AtalkAspCConnDereference(
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Close = FALSE;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT (VALID_ASPCCO(pAspConn));
|
|
|
|
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_REFASPADDR,
|
|
("AtalkAspCConnDereference: %lx, %d\n",
|
|
pAspConn, pAspConn->aspcco_RefCount-1));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAspConn->aspcco_Lock, &OldIrql);
|
|
if (--(pAspConn->aspcco_RefCount) == 0)
|
|
{
|
|
ASSERT(pAspConn->aspcco_Flags & ASPCCO_CLOSING);
|
|
Close = TRUE;
|
|
}
|
|
RELEASE_SPIN_LOCK(&pAspConn->aspcco_Lock, OldIrql);
|
|
|
|
if (Close)
|
|
{
|
|
if (pAspConn->aspcco_CloseComp != NULL)
|
|
(*pAspConn->aspcco_CloseComp)(ATALK_NO_ERROR,
|
|
pAspConn->aspcco_CloseCtx);
|
|
|
|
atalkAspCDeQueueConnGlobalList(pAspConn);
|
|
|
|
// Finally free the memory
|
|
AtalkFreeMemory(pAspConn);
|
|
|
|
AtalkUnlockAspCIfNecessary();
|
|
}
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCQueueAddrGlobalList(
|
|
IN PASPC_ADDROBJ pAspAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&atalkAspCLock, &OldIrql);
|
|
AtalkLinkDoubleAtHead(atalkAspCAddrList, pAspAddr, aspcao_Next, aspcao_Prev);
|
|
RELEASE_SPIN_LOCK(&atalkAspCLock, OldIrql);
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCDeQueueAddrGlobalList(
|
|
IN PASPC_ADDROBJ pAspAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&atalkAspCLock, &OldIrql);
|
|
AtalkUnlinkDouble(pAspAddr, aspcao_Next, aspcao_Prev);
|
|
RELEASE_SPIN_LOCK(&atalkAspCLock, OldIrql);
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCQueueConnGlobalList(
|
|
IN PASPC_CONNOBJ pAspConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&atalkAspCLock, &OldIrql);
|
|
AtalkLinkDoubleAtHead(atalkAspCConnList, pAspConn, aspcco_Next, aspcco_Prev);
|
|
RELEASE_SPIN_LOCK(&atalkAspCLock, OldIrql);
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
atalkAspCDeQueueConnGlobalList(
|
|
IN PASPC_CONNOBJ pAspCConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&atalkAspCLock, &OldIrql);
|
|
AtalkUnlinkDouble(pAspCConn, aspcco_Next, aspcco_Prev);
|
|
RELEASE_SPIN_LOCK(&atalkAspCLock, OldIrql);
|
|
}
|