windows-nt/Source/XPSP1/NT/net/sfm/atalk/sys/aspc.c

1489 lines
29 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}