2778 lines
68 KiB
C
2778 lines
68 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
asp.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the ASP 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 ASP
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT, AtalkInitAspInitialize)
|
||
#pragma alloc_text(PAGE, AtalkAspCreateAddress)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspCloseAddress)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspSetStatus)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspListenControl)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspCloseConnection)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspFreeConnection)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspCleanupConnection)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspWriteContinue)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspReply)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspPostWriteContinue)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspSendAttention)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspReferenceAddr)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspReferenceConnBySrcAddr)
|
||
#pragma alloc_text(PAGE_ASP, AtalkAspDereferenceConn)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspSlsXHandler)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspSssXHandler)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspReplyRelease)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspWriteContinueResp)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspSendAttentionResp)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspSessionClose)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspReturnResp)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspRespComplete)
|
||
#pragma alloc_text(PAGE_ASP, atalkAspCloseComplete)
|
||
#endif
|
||
|
||
/*
|
||
* The model for ASP calls in this module is as follows:
|
||
*
|
||
* - For create calls (CreateAddress & CreateSession), a pointer to the created
|
||
* object is returned. This structure is referenced for creation.
|
||
* - For all other calls, it expects a referenced pointer to the object.
|
||
*/
|
||
|
||
|
||
VOID
|
||
AtalkInitAspInitialize(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
LONG i;
|
||
|
||
INITIALIZE_SPIN_LOCK(&atalkAspLock);
|
||
|
||
for (i = 0; i < NUM_ASP_CONN_LISTS; i++)
|
||
{
|
||
AtalkTimerInitialize(&atalkAspConnMaint[i].ascm_SMTTimer,
|
||
atalkAspSessionMaintenanceTimer,
|
||
(SHORT)(ASP_SESSION_MAINTENANCE_TIMER - i*ASP_SESSION_TIMER_STAGGER));
|
||
AtalkTimerScheduleEvent(&atalkAspConnMaint[i].ascm_SMTTimer);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
ATALK_ERROR
|
||
AtalkAspCreateAddress(
|
||
OUT PASP_ADDROBJ * ppAspAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create an ASP address object (aka listener). This object is associated with
|
||
two seperate Atp sockets, one each for the Sls and the Sss. The Sls accepts
|
||
the tickle, getstatus and opensession requests from the client end. The
|
||
Sss accepts requests.
|
||
|
||
Currently only the server side ASP is implemented and hence the ASP address
|
||
object is only a listener.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_ADDROBJ pAspAddr = NULL;
|
||
ATALK_ERROR Status;
|
||
int i;
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCreateAddr: Entered\n"));
|
||
|
||
do
|
||
{
|
||
// Allocate memory for the Asp address object
|
||
if ((pAspAddr = AtalkAllocZeroedMemory(sizeof(ASP_ADDROBJ))) == NULL)
|
||
{
|
||
Status = ATALK_RESR_MEM;
|
||
break;
|
||
}
|
||
|
||
// Initialize the Asp address object
|
||
#if DBG
|
||
pAspAddr->aspao_Signature = ASPAO_SIGNATURE;
|
||
#endif
|
||
INITIALIZE_SPIN_LOCK(&pAspAddr->aspao_Lock);
|
||
|
||
// Refcounts for creation, Sls & Sss sockets and request handlers
|
||
pAspAddr->aspao_RefCount = 1 + 2 + 2;
|
||
pAspAddr->aspao_NextSessionId = 1;
|
||
pAspAddr->aspao_EnableNewConnections = TRUE;
|
||
|
||
// 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,
|
||
TRUE, // CACHE this address
|
||
&pAspAddr->aspao_pSlsAtpAddr);
|
||
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCreateAddress: AtalkAtpOpenAddress for Sls failed %ld\n", Status));
|
||
break;
|
||
}
|
||
|
||
// Set Request handler for the SLS to handle GetStatus, OpenSession and Tickle
|
||
AtalkAtpSetReqHandler(pAspAddr->aspao_pSlsAtpAddr,
|
||
atalkAspSlsXHandler,
|
||
pAspAddr);
|
||
|
||
// Create the Atp Socket on the port for the Sss
|
||
Status = AtalkAtpOpenAddress(AtalkDefaultPort,
|
||
0,
|
||
NULL,
|
||
ATP_DEF_MAX_SINGLE_PKT_SIZE,
|
||
ATP_DEF_SEND_USER_BYTES_ALL,
|
||
NULL,
|
||
TRUE, // CACHE this address
|
||
&pAspAddr->aspao_pSssAtpAddr);
|
||
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCreateAddress: AtalkAtpOpenAddress for Sss failed %ld\n", Status));
|
||
break;
|
||
}
|
||
|
||
// Set Request handler for the SSS to handle Cmd/Write/Close
|
||
AtalkAtpSetReqHandler(pAspAddr->aspao_pSssAtpAddr,
|
||
atalkAspSssXHandler,
|
||
pAspAddr);
|
||
} while (FALSE);
|
||
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
if (pAspAddr != NULL)
|
||
{
|
||
if (pAspAddr->aspao_pSlsAtpAddr != NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCreateAddress: Closing SLS Atp Address %lx\n",
|
||
pAspAddr->aspao_pSlsAtpAddr));
|
||
AtalkAtpCloseAddress(pAspAddr->aspao_pSlsAtpAddr, NULL, NULL);
|
||
}
|
||
if (pAspAddr->aspao_pSssAtpAddr != NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCreateAddress: Closing SSS Atp Address %lx\n",
|
||
pAspAddr->aspao_pSssAtpAddr));
|
||
AtalkAtpCloseAddress(pAspAddr->aspao_pSssAtpAddr, NULL, NULL);
|
||
}
|
||
AtalkFreeMemory(pAspAddr);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*ppAspAddr = pAspAddr;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
|
||
ATALK_ERROR
|
||
AtalkAspCloseAddress(
|
||
IN PASP_ADDROBJ pAspAddr,
|
||
IN GENERIC_COMPLETION CompletionRoutine,
|
||
IN PVOID CloseContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn;
|
||
KIRQL OldIrql;
|
||
int i;
|
||
ATALK_ERROR Status = ATALK_PENDING;
|
||
PBYTE pStatusBuf;
|
||
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
ASSERT(pAspAddr->aspao_RefCount > 1);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCloseAddr: Entered for Addr %lx\n", pAspAddr));
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
|
||
pAspAddr->aspao_Flags |= ASPAO_CLOSING;
|
||
|
||
pAspAddr->aspao_CloseCompletion = CompletionRoutine;
|
||
pAspAddr->aspao_CloseContext = CloseContext;
|
||
|
||
pStatusBuf = pAspAddr->aspao_pStatusBuf;
|
||
pAspAddr->aspao_pStatusBuf = NULL;
|
||
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
// Close down the atp sockets for Sls and Sss
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspCloseAddress: Closing SLS Atp Address %lx\n",
|
||
pAspAddr->aspao_pSlsAtpAddr));
|
||
|
||
AtalkAtpCloseAddress(pAspAddr->aspao_pSlsAtpAddr,
|
||
atalkAspCloseComplete,
|
||
pAspAddr);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspCloseAddress: Closing SSS Atp Address %lx\n",
|
||
pAspAddr->aspao_pSssAtpAddr));
|
||
|
||
AtalkAtpCloseAddress(pAspAddr->aspao_pSssAtpAddr,
|
||
atalkAspCloseComplete,
|
||
pAspAddr);
|
||
|
||
// Free the status buffer if any
|
||
if (pStatusBuf != NULL)
|
||
{
|
||
AtalkFreeMemory(pStatusBuf);
|
||
}
|
||
|
||
// Shut down the active sessions now.
|
||
for (i = 0; i < ASP_CONN_HASH_BUCKETS; i++)
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
pAspConn = pAspAddr->aspao_pSessions[i];
|
||
while (pAspConn != NULL)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
// if we have visited this guy, skip it
|
||
if (pAspConn->aspco_Flags & ASPCO_SHUTDOWN)
|
||
{
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCloseAddress: VISITED: skipping conn %lx Flags %lx RefCount %d\n",
|
||
pAspConn,pAspConn->aspco_Flags,pAspConn->aspco_RefCount));
|
||
|
||
// we still have the pAspAddr->aspao_Lock spinlock held!
|
||
pAspConn = pAspConn->aspco_NextOverflow;
|
||
continue;
|
||
}
|
||
|
||
pAspConn->aspco_Flags |= (ASPCO_LOCAL_CLOSE | ASPCO_SHUTDOWN);
|
||
|
||
// Reference this since atalkAspSessionClose() expects it.
|
||
pAspConn->aspco_RefCount ++;
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
atalkAspSessionClose(pAspConn);
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
}
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
}
|
||
|
||
ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
|
||
|
||
// Let remaining cleanup happen during the Derefernce
|
||
AtalkAspDereferenceAddr(pAspAddr); // Remove the creation reference
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
|
||
ATALK_ERROR
|
||
AtalkAspBind(
|
||
IN PASP_ADDROBJ pAspAddr,
|
||
IN PASP_BIND_PARAMS pBindParms,
|
||
IN PACTREQ pActReq
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
|
||
ASSERT (VALID_ASPAO(pAspAddr));
|
||
|
||
// copy network addr
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
pBindParms->pXportEntries->asp_AtalkAddr.Network =
|
||
pAspAddr->aspao_pSlsAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Network;
|
||
pBindParms->pXportEntries->asp_AtalkAddr.Node =
|
||
pAspAddr->aspao_pSlsAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Node;
|
||
pBindParms->pXportEntries->asp_AtalkAddr.Socket =
|
||
pAspAddr->aspao_pSlsAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Socket;
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
// Fill in our entry points into the client buffer
|
||
pBindParms->pXportEntries->asp_AspCtxt = pAspAddr;
|
||
pBindParms->pXportEntries->asp_SetStatus = AtalkAspSetStatus;
|
||
pBindParms->pXportEntries->asp_CloseConn = AtalkAspCloseConnection;
|
||
pBindParms->pXportEntries->asp_FreeConn = AtalkAspFreeConnection;
|
||
pBindParms->pXportEntries->asp_ListenControl = AtalkAspListenControl;
|
||
pBindParms->pXportEntries->asp_WriteContinue = AtalkAspWriteContinue;
|
||
pBindParms->pXportEntries->asp_Reply = AtalkAspReply;
|
||
pBindParms->pXportEntries->asp_SendAttention = AtalkAspSendAttention;
|
||
|
||
// Get the clients entry points
|
||
pAspAddr->aspao_ClientEntries = pBindParms->ClientEntries;
|
||
|
||
// Call the completion routine before returning.
|
||
(*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq);
|
||
|
||
return ATALK_PENDING;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
AtalkAspSetStatus(
|
||
IN PASP_ADDROBJ pAspAddr,
|
||
IN PUCHAR pStatusBuf,
|
||
IN USHORT StsBufSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PUCHAR pOldBuf = NULL, pNewBuf = NULL;
|
||
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspSetStatus: Entered for Addr %lx\n", pAspAddr));
|
||
|
||
do
|
||
{
|
||
if (pStatusBuf != NULL)
|
||
{
|
||
// Allocate a buffer and copy the contents of the passed in
|
||
// buffer descriptor in it. Free an existing status buffer if one exists
|
||
if (StsBufSize >= ASP_MAX_STATUS_SIZE)
|
||
{
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
break;
|
||
}
|
||
|
||
if ((pNewBuf = AtalkAllocMemory(StsBufSize)) == NULL)
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
RtlCopyMemory(pNewBuf, pStatusBuf, StsBufSize);
|
||
}
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
|
||
if (pAspAddr->aspao_pStatusBuf != NULL)
|
||
{
|
||
ASSERT(pAspAddr->aspao_StsBufSize != 0);
|
||
pOldBuf = pAspAddr->aspao_pStatusBuf;
|
||
}
|
||
|
||
pAspAddr->aspao_pStatusBuf = pNewBuf;
|
||
pAspAddr->aspao_StsBufSize = StsBufSize;
|
||
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
if (pOldBuf != NULL)
|
||
AtalkFreeMemory(pOldBuf);
|
||
} while (FALSE);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS FASTCALL
|
||
AtalkAspListenControl(
|
||
IN PASP_ADDROBJ pAspAddr,
|
||
IN BOOLEAN Enable
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||
|
||
if (AtalkAspReferenceAddr(pAspAddr))
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
pAspAddr->aspao_EnableNewConnections = Enable;
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
AtalkAspDereferenceAddr(pAspAddr);
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
AtalkAspCloseConnection(
|
||
IN PASP_CONNOBJ pAspConn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Shutdown a session.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
BOOLEAN CompListen = FALSE;
|
||
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
ASSERT(pAspConn->aspco_RefCount > 0);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCloseConn: Entered for Conn %lx\n", pAspConn));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkCloseConnection: Close session from %d.%d for Session %d\n",
|
||
pAspConn->aspco_WssRemoteAddr.ata_Network,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Node,
|
||
pAspConn->aspco_SessionId));
|
||
|
||
AtalkAspCleanupConnection(pAspConn);
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
|
||
pAspConn->aspco_Flags |= (ASPCO_CLOSING | ASPCO_LOCAL_CLOSE);
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCloseConnection: Done for %lx (%ld)\n",
|
||
pAspConn, pAspConn->aspco_RefCount));
|
||
|
||
// Let remaining cleanup happen during the Derefernce
|
||
AtalkAspDereferenceConn(pAspConn); // Remove the creation reference
|
||
|
||
#ifdef PROFILING
|
||
INTERLOCKED_DECREMENT_LONG( &AtalkStatistics.stat_CurAspSessions,
|
||
&AtalkStatsLock.SpinLock);
|
||
#endif
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
AtalkAspFreeConnection(
|
||
IN PASP_CONNOBJ pAspConn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Shutdown a session.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
ATALK_ERROR
|
||
AtalkAspCleanupConnection(
|
||
IN PASP_CONNOBJ pAspConn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Cancel all I/O on this session. Complete pending replies and write
|
||
continues with error.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_REQUEST pAspReq;
|
||
PASP_ADDROBJ pAspAddr;
|
||
ATALK_ERROR Status;
|
||
KIRQL OldIrql;
|
||
USHORT XactId;
|
||
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
||
ATALK_ADDR RemoteAddr;
|
||
BOOLEAN CancelTickle, AlreadyCleaning, fConnActive;
|
||
ATALK_ERROR error;
|
||
|
||
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCleanupConnection: For %lx\n", pAspConn));
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
CancelTickle = ((pAspConn->aspco_Flags & ASPCO_TICKLING) != 0);
|
||
|
||
AlreadyCleaning = (pAspConn->aspco_Flags & ASPCO_CLEANING_UP) ? TRUE : FALSE;
|
||
|
||
if (AlreadyCleaning)
|
||
{
|
||
pAspConn->aspco_Flags &= ~ASPCO_TICKLING;
|
||
}
|
||
fConnActive = (pAspConn->aspco_Flags & ASPCO_ACTIVE) ? TRUE : FALSE;
|
||
|
||
pAspConn->aspco_Flags &= ~ASPCO_ACTIVE;
|
||
|
||
pAspConn->aspco_Flags |= ASPCO_CLEANING_UP;
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
if (AlreadyCleaning)
|
||
return ATALK_NO_ERROR;
|
||
|
||
pAspAddr = pAspConn->aspco_pAspAddr;
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
// Send a session close request, if this is an active connection
|
||
if (fConnActive)
|
||
{
|
||
UserBytes[ASP_CMD_OFF] = ASP_CLOSE_SESSION;
|
||
UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
|
||
PUTSHORT2SHORT(UserBytes + ASP_ATTN_WORD_OFF, 0);
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCleanupConnection: Sending close req for %lx\n",
|
||
pAspConn));
|
||
Status = AtalkAtpPostReq(pAspAddr->aspao_pSssAtpAddr,
|
||
&pAspConn->aspco_WssRemoteAddr,
|
||
&XactId,
|
||
ATP_REQ_REMOTE, // Close session request is ALO
|
||
NULL,
|
||
0,
|
||
UserBytes,
|
||
NULL,
|
||
0,
|
||
ATP_RETRIES_FOR_ASP,
|
||
ATP_MAX_INTERVAL_FOR_ASP,
|
||
THIRTY_SEC_TIMER,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCleanupConn: AtalkAtpPostReq %ld\n", Status));
|
||
}
|
||
}
|
||
|
||
// Cancel tickle packets
|
||
if (CancelTickle)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCleanupConnection: Cancel tickle for %lx\n", pAspConn));
|
||
Status = AtalkAtpCancelReq(pAspAddr->aspao_pSlsAtpAddr,
|
||
pAspConn->aspco_TickleXactId,
|
||
&pAspConn->aspco_WssRemoteAddr);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCleanupConn: AtalkAtpCancelReq %ld\n", Status));
|
||
}
|
||
}
|
||
|
||
do
|
||
{
|
||
BOOLEAN CancelReply = FALSE;
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
for (pAspReq = pAspConn->aspco_pActiveReqs;
|
||
pAspReq != NULL;
|
||
pAspReq = pAspReq->asprq_Next)
|
||
{
|
||
ASSERT (VALID_ASPRQ(pAspReq));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCleanupConnection: Found req %lx (%lx) for %lx\n",
|
||
pAspReq, pAspReq->asprq_Flags, pAspConn));
|
||
|
||
CancelReply = FALSE;
|
||
|
||
if ((pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_WRTCONT_CANCELLED)) == ASPRQ_WRTCONT)
|
||
{
|
||
pAspReq->asprq_Flags |= ASPRQ_WRTCONT_CANCELLED;
|
||
RemoteAddr = pAspConn->aspco_WssRemoteAddr;
|
||
break;
|
||
}
|
||
if ((pAspReq->asprq_Flags & (ASPRQ_REPLY | ASPRQ_REPLY_CANCELLED)) == ASPRQ_REPLY)
|
||
{
|
||
CancelReply = TRUE;
|
||
pAspReq->asprq_Flags |= ASPRQ_REPLY_CANCELLED;
|
||
break;
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
if (pAspReq != NULL)
|
||
{
|
||
if (CancelReply)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCleanupConnection: Cancel reply for %lx, flag=%lx\n",
|
||
pAspReq,pAspReq->asprq_Flags));
|
||
|
||
error = AtalkAtpCancelResp(pAspReq->asprq_pAtpResp);
|
||
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCleanupConnection: AtalkAtpCancelResp failed %lx\n",error));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspCleanupConnection: Cancel wrtcont for %lx, flag=%lx\n",
|
||
pAspReq,pAspReq->asprq_Flags));
|
||
|
||
error = AtalkAtpCancelReq(pAspConn->aspco_pAspAddr->aspao_pSssAtpAddr,
|
||
pAspReq->asprq_WCXactId,
|
||
&RemoteAddr);
|
||
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspCleanupConnection: AtalkAtpCancelReq failed %lx\n",error));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
} while (TRUE);
|
||
|
||
return ATALK_NO_ERROR;
|
||
}
|
||
|
||
NTSTATUS FASTCALL
|
||
AtalkAspWriteContinue(
|
||
IN PREQUEST pRequest
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The response buffer is in the request itself.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
PASP_REQUEST pAspReq;
|
||
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspWriteContinue: Entered with pRequest %lx\n", pRequest));
|
||
|
||
pAspReq = CONTAINING_RECORD(pRequest, ASP_REQUEST, asprq_Request);
|
||
ASSERT (VALID_ASPRQ(pAspReq));
|
||
|
||
if (pRequest->rq_WriteMdl != NULL)
|
||
{
|
||
atalkAspPostWriteContinue(pAspReq);
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspWriteContinue: buffer alloc failed, completing write with error\n"));
|
||
|
||
atalkAspWriteContinueResp(ATALK_RESR_MEM, pAspReq, NULL, NULL, 0, NULL);
|
||
}
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
NTSTATUS FASTCALL
|
||
AtalkAspReply(
|
||
IN PREQUEST pRequest, // Pointer to request
|
||
IN PBYTE pResultCode // Pointer to the 4-byte result
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The response buffer is in the request itself.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_REQUEST pAspReq, *ppAspReq;
|
||
PASP_CONNOBJ pAspConn;
|
||
PASP_ADDROBJ pAspAddr;
|
||
ATALK_ERROR error;
|
||
KIRQL OldIrql;
|
||
USHORT ReplySize;
|
||
|
||
pAspReq = CONTAINING_RECORD(pRequest, ASP_REQUEST, asprq_Request);
|
||
ASSERT (VALID_ASPRQ(pAspReq));
|
||
|
||
pAspConn = pAspReq->asprq_pAspConn;
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
|
||
pAspAddr = pAspConn->aspco_pAspAddr;
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspReply: Entered for session %lx\n", pAspConn));
|
||
|
||
ASSERT ((pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_REPLY)) == 0);
|
||
|
||
do
|
||
{
|
||
// Find and de-queue this request from the list
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
|
||
for (ppAspReq = &pAspConn->aspco_pActiveReqs;
|
||
*ppAspReq != NULL;
|
||
ppAspReq = &(*ppAspReq)->asprq_Next)
|
||
{
|
||
if (pAspReq == *ppAspReq)
|
||
{
|
||
*ppAspReq = pAspReq->asprq_Next;
|
||
pAspConn->aspco_cReqsInProcess --;
|
||
pAspReq->asprq_Flags |= ASPRQ_REPLY;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT(*ppAspReq == pAspReq->asprq_Next);
|
||
|
||
if (pAspConn->aspco_Flags & (ASPCO_CLEANING_UP |
|
||
ASPCO_CLOSING |
|
||
ASPCO_LOCAL_CLOSE |
|
||
ASPCO_REMOTE_CLOSE))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspReply: Session Closing - session %x\n", pAspConn->aspco_SessionId));
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
pAspReq->asprq_Flags &= ~ASPRQ_REPLY;
|
||
pAspReq->asprq_Flags |= ASPRQ_REPLY_ABORTED;
|
||
error = ATALK_LOCAL_CLOSE;
|
||
break;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
ReplySize = (USHORT)AtalkSizeMdlChain(pAspReq->asprq_Request.rq_ReplyMdl);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspReply: Posting AtalkAtpPostResp for request %lx\n", pAspReq));
|
||
|
||
error = AtalkAtpPostResp(pAspReq->asprq_pAtpResp,
|
||
&pAspReq->asprq_RemoteAddr,
|
||
pAspReq->asprq_Request.rq_ReplyMdl,
|
||
ReplySize,
|
||
pResultCode,
|
||
atalkAspReplyRelease,
|
||
pAspReq);
|
||
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspReply: AtalkAtpPostResp %ld\n", error));
|
||
}
|
||
} while (FALSE);
|
||
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
if (error != ATALK_ATP_RESP_TOOMANY)
|
||
{
|
||
atalkAspReplyRelease(error, pAspReq);
|
||
}
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspReply: Completing request %lx, Status %ld\n",
|
||
pAspReq, error));
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL ATALK_ERROR FASTCALL
|
||
atalkAspPostWriteContinue(
|
||
IN PASP_REQUEST pAspReq
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ATALK_ERROR error;
|
||
PASP_CONNOBJ pAspConn;
|
||
PAMDL pAMdl = NULL;
|
||
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
||
USHORT RespSize;
|
||
|
||
ASSERT (VALID_ASPRQ(pAspReq));
|
||
|
||
pAspConn = pAspReq->asprq_pAspConn;
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspPostWriteContinue: Entered for session %lx\n", pAspConn));
|
||
|
||
RespSize = (USHORT)AtalkSizeMdlChain(pAspReq->asprq_Request.rq_WriteMdl);
|
||
ASSERT (RespSize <= ATP_MAX_TOTAL_RESPONSE_SIZE);
|
||
|
||
if (RespSize > ATP_MAX_TOTAL_RESPONSE_SIZE)
|
||
RespSize = ATP_MAX_TOTAL_RESPONSE_SIZE;
|
||
|
||
ASSERT (!(pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_WRTCONT_CANCELLED)));
|
||
|
||
pAspReq->asprq_Flags |= ASPRQ_WRTCONT;
|
||
|
||
do
|
||
{
|
||
// We need to build an AMdl for two bytes of response which
|
||
// indicates how much data we are expecting !!!
|
||
if ((pAMdl = AtalkAllocAMdl(pAspReq->asprq_WrtContRespBuf,
|
||
ASP_WRITE_DATA_SIZE)) == NULL)
|
||
{
|
||
error = ATALK_RESR_MEM;
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspWriteContinue: AtalkAllocMdl failed for 2 bytes !!\n"));
|
||
}
|
||
|
||
else
|
||
{
|
||
PBYTE pWrtData;
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspWriteContinue: Posting AtalkAtpPostReq for request %lx\n",
|
||
pAspReq));
|
||
|
||
pWrtData = AtalkGetAddressFromMdlSafe(pAMdl, NormalPagePriority);
|
||
if (pWrtData == NULL)
|
||
{
|
||
if (pAMdl != NULL)
|
||
{
|
||
AtalkFreeAMdl(pAMdl);
|
||
}
|
||
error = ATALK_RESR_MEM;
|
||
break;
|
||
}
|
||
|
||
UserBytes[ASP_CMD_OFF] = ASP_WRITE_DATA;
|
||
UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
|
||
PUTSHORT2SHORT(UserBytes+ASP_SEQUENCE_NUM_OFF, pAspReq->asprq_SeqNum);
|
||
PUTSHORT2SHORT(pWrtData, RespSize);
|
||
|
||
// Snapshot the current tick count. We use this to adjust the retry times on
|
||
// write continue.
|
||
pAspConn->aspco_RT.rt_New = AtalkGetCurrentTick();
|
||
error = AtalkAtpPostReq(pAspConn->aspco_pAspAddr->aspao_pSssAtpAddr,
|
||
&pAspConn->aspco_WssRemoteAddr,
|
||
&pAspReq->asprq_WCXactId,
|
||
ATP_REQ_EXACTLY_ONCE | ATP_REQ_REMOTE,
|
||
pAMdl,
|
||
ASP_WRITE_DATA_SIZE,
|
||
UserBytes,
|
||
pAspReq->asprq_Request.rq_WriteMdl,
|
||
RespSize,
|
||
ATP_INFINITE_RETRIES,
|
||
pAspConn->aspco_RT.rt_Base,
|
||
THIRTY_SEC_TIMER,
|
||
atalkAspWriteContinueResp,
|
||
pAspReq);
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspWriteContinue: AtalkAtpPostReq %ld\n", error));
|
||
}
|
||
}
|
||
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
if (pAMdl != NULL)
|
||
AtalkFreeAMdl(pAMdl);
|
||
}
|
||
} while (FALSE);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
AtalkAspSendAttention(
|
||
IN PASP_CONNOBJ pAspConn,
|
||
IN USHORT AttentionWord,
|
||
IN PVOID pContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ATALK_ERROR error;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
KIRQL OldIrql;
|
||
PAMDL pAMdl = NULL;
|
||
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
||
USHORT XactId, RespSize = 16; // Some small number (see comment below)
|
||
|
||
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspSendAttention: Entered for session %lx\n", pAspConn));
|
||
|
||
// Reference by src addr here instead of by pointer since the former will
|
||
// fail when the session is in one of the stages of death whereas the
|
||
// latter will not. Also this assumes that it is called at dispatch so raise irql.
|
||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
pAspConn = atalkAspReferenceConnBySrcAddr(pAspConn->aspco_pAspAddr,
|
||
&pAspConn->aspco_WssRemoteAddr,
|
||
pAspConn->aspco_SessionId);
|
||
KeLowerIrql(OldIrql);
|
||
|
||
if (pAspConn == NULL)
|
||
return STATUS_REQUEST_NOT_ACCEPTED;
|
||
|
||
UserBytes[ASP_CMD_OFF] = ASP_ATTENTION;
|
||
UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
|
||
PUTSHORT2SHORT(UserBytes+ASP_ATTN_WORD_OFF, AttentionWord);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspSendAttention: Posting AtalkAtpPostReq for Conn %lx\n", pAspConn));
|
||
|
||
// We need to build an AMdl for a dummy buffer to hold the response.
|
||
// There is no real response but some clients fry their
|
||
// machines if we don't !!! If we cannot allocate the mdl we we go
|
||
// ahead anyway.
|
||
if ((pAMdl = AtalkAllocAMdl(NULL, RespSize)) == NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspSendAttention: AtalkAllocMdl failed for dummy buffer !!\n"));
|
||
RespSize = 0;
|
||
}
|
||
pAspConn->aspco_AttentionContext = pContext;
|
||
|
||
error = AtalkAtpPostReq(pAspConn->aspco_pAspAddr->aspao_pSssAtpAddr,
|
||
&pAspConn->aspco_WssRemoteAddr,
|
||
&XactId,
|
||
ATP_REQ_REMOTE, // SendAttention is ALO
|
||
NULL,
|
||
0,
|
||
UserBytes,
|
||
pAMdl,
|
||
RespSize,
|
||
ATP_RETRIES_FOR_ASP,
|
||
ATP_MAX_INTERVAL_FOR_ASP,
|
||
THIRTY_SEC_TIMER,
|
||
atalkAspSendAttentionResp,
|
||
pAspConn);
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspSendAttention: AtalkAtpPostReq %ld\n", Status));
|
||
Status = AtalkErrorToNtStatus(error);
|
||
atalkAspSendAttentionResp(error,
|
||
pAspConn,
|
||
NULL,
|
||
pAMdl,
|
||
RespSize,
|
||
UserBytes);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
|
||
PASP_ADDROBJ FASTCALL
|
||
AtalkAspReferenceAddr(
|
||
IN PASP_ADDROBJ pAspAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
PASP_ADDROBJ pRefAddr;
|
||
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspReferenceAddr: Addr %lx, PreCount %ld\n",
|
||
pAspAddr, pAspAddr->aspao_RefCount));
|
||
|
||
pRefAddr = pAspAddr;
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
|
||
ASSERT(pAspAddr->aspao_RefCount > 1);
|
||
|
||
if (pAspAddr->aspao_Flags & ASPAO_CLOSING)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("AtalkAspReferenceAddr: Referencing closing object %lx!!\n",
|
||
pAspAddr));
|
||
pRefAddr = NULL;
|
||
}
|
||
else pAspAddr->aspao_RefCount ++;
|
||
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
return pRefAddr;
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID FASTCALL
|
||
AtalkAspDereferenceAddr(
|
||
IN PASP_ADDROBJ pAspAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
BOOLEAN Cleanup;
|
||
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
ASSERT (pAspAddr->aspao_RefCount > 0);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspDereferenceAddr: Addr %lx, PreCount %ld\n",
|
||
pAspAddr, pAspAddr->aspao_RefCount));
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
|
||
pAspAddr->aspao_RefCount --;
|
||
|
||
Cleanup = FALSE;
|
||
if (pAspAddr->aspao_RefCount == 0)
|
||
{
|
||
ASSERT (pAspAddr->aspao_Flags & ASPAO_CLOSING);
|
||
Cleanup = TRUE;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
// Check if this address object is history. Do all the processing needed to make this go
|
||
// away. When all is done, clear the event to signal close is complete
|
||
if (Cleanup)
|
||
{
|
||
// At this point we are sure that no active sessions exist on this
|
||
// address.
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspDereferenceAddr: Cleaning up addr %lx\n", pAspAddr));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspDereferenceAddr: Indicating close for %lx\n", pAspAddr));
|
||
|
||
ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
|
||
|
||
// Call the completion routine to indicate close is successfull
|
||
if (pAspAddr->aspao_CloseCompletion != NULL)
|
||
(*pAspAddr->aspao_CloseCompletion)(ATALK_NO_ERROR,
|
||
pAspAddr->aspao_CloseContext);
|
||
// Finally free the memory
|
||
AtalkFreeMemory(pAspAddr);
|
||
|
||
AtalkUnlockAspIfNecessary();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
LOCAL PASP_CONNOBJ
|
||
atalkAspReferenceConnBySrcAddr(
|
||
IN PASP_ADDROBJ pAspAddr,
|
||
IN PATALK_ADDR pSrcAddr,
|
||
IN BYTE SessionId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ASP has the concept of 8-bit session ids which uniquely identifies a
|
||
session on a listener. This effectively restricts the number of sessions
|
||
to 255 (0 is invalid). To eliminate the restriction, the following
|
||
strategy is used.
|
||
a, Atp is modified to isolate the transaction ids on a per addr basis
|
||
i.e. it monotonically increases for each <net,node,socket> combination.
|
||
b, We create session ids on a per <net,node> basis.
|
||
|
||
Given the following observed facts:
|
||
1, That macintoshes use the sockets starting from the top of the range.
|
||
2, Most network addresses have the same high byte - macintoshes tend
|
||
to start from the bottom of the range.
|
||
3, We allocate session ids starting from 1 and most (all) clients will
|
||
not have more than one session with us.
|
||
|
||
It does not make any sense to take either the socket, session id or the
|
||
high byte of the network number into account. That leaves only the low
|
||
byte of the network, and node id - a nice 16-bit number to hash.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn, pRefConn = NULL;
|
||
int index;
|
||
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspReferenceConnBySrcAddr: Addr %lx, Source %x.%x SessionId %d\n",
|
||
pAspAddr, pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
||
|
||
index = HASH_SRCADDR(pSrcAddr);
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
for (pAspConn = pAspAddr->aspao_pSessions[index];
|
||
pAspConn != NULL;
|
||
pAspConn = pAspConn->aspco_NextOverflow)
|
||
{
|
||
if ((pSrcAddr->ata_Network == pAspConn->aspco_WssRemoteAddr.ata_Network) &&
|
||
(pSrcAddr->ata_Node == pAspConn->aspco_WssRemoteAddr.ata_Node) &&
|
||
(pAspConn->aspco_SessionId == SessionId))
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
if ((pAspConn->aspco_Flags & (ASPCO_CLOSING |
|
||
ASPCO_CLEANING_UP |
|
||
ASPCO_LOCAL_CLOSE |
|
||
ASPCO_REMOTE_CLOSE)) == 0)
|
||
{
|
||
ASSERT(pAspConn->aspco_RefCount > 0);
|
||
pAspConn->aspco_RefCount ++;
|
||
|
||
pRefConn = pAspConn;
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
break;
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
return pRefConn;
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID FASTCALL
|
||
AtalkAspDereferenceConn(
|
||
IN PASP_CONNOBJ pAspConn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_ADDROBJ pAspAddr = pAspConn->aspco_pAspAddr;
|
||
KIRQL OldIrql;
|
||
PASP_REQUEST pAspReq;
|
||
BOOLEAN Cleanup = FALSE;
|
||
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
|
||
ASSERT (pAspConn->aspco_RefCount > 0);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("AtalkAspDereferenceConn: Conn %lx, PreCount %ld\n",
|
||
pAspConn, pAspConn->aspco_RefCount));
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
|
||
pAspConn->aspco_RefCount --;
|
||
|
||
if (pAspConn->aspco_RefCount == 0)
|
||
{
|
||
Cleanup = TRUE;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
if (!Cleanup)
|
||
{
|
||
return;
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspDereferenceConn: Last for %lx\n", pAspConn));
|
||
|
||
// The connection is all but dead. Perform the last rites. If its an
|
||
// active session that we're about to shut down, send a close notification
|
||
// to the other side. If it is a remote close, we've already responded to it.
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspDereferenceConn: Cleaning up Conn %lx\n", pAspConn));
|
||
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
// The connection is in one of the following states:
|
||
// a, Closed remotely - idle
|
||
// b, Active
|
||
//
|
||
// In either case it is in the hash bucket so unlink it
|
||
{
|
||
PASP_CONNOBJ * ppAspConn;
|
||
int index;
|
||
|
||
// The connection was active. This is linked into two different
|
||
// lists. Unlink from the hash table here and from the global
|
||
// list later.
|
||
ASSERT(pAspConn->aspco_pActiveReqs == NULL);
|
||
index = HASH_SRCADDR(&pAspConn->aspco_WssRemoteAddr);
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspAddr->aspao_Lock, &OldIrql);
|
||
for (ppAspConn = &pAspAddr->aspao_pSessions[index];
|
||
*ppAspConn != NULL;
|
||
ppAspConn = &(*ppAspConn)->aspco_NextOverflow)
|
||
{
|
||
if (pAspConn == *ppAspConn)
|
||
{
|
||
*ppAspConn = pAspConn->aspco_NextOverflow;
|
||
break;
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK(&pAspAddr->aspao_Lock, OldIrql);
|
||
|
||
ASSERT (*ppAspConn == pAspConn->aspco_NextOverflow);
|
||
}
|
||
|
||
ACQUIRE_SPIN_LOCK(&atalkAspLock, &OldIrql);
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
AtalkUnlinkDouble(pAspConn,
|
||
aspco_NextSession,
|
||
aspco_PrevSession)
|
||
|
||
|
||
// Free any requests on the free list
|
||
while ((pAspReq = pAspConn->aspco_pFreeReqs) != NULL)
|
||
{
|
||
pAspConn->aspco_pFreeReqs = pAspReq->asprq_Next;
|
||
AtalkBPFreeBlock(pAspReq);
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
RELEASE_SPIN_LOCK(&atalkAspLock, OldIrql);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("AtalkAspDereferenceConn: Indicating close for Conn %lx\n", pAspConn));
|
||
|
||
// Call the completion routine to indicate close is successful.
|
||
(*pAspAddr->aspao_ClientEntries.clt_CloseCompletion)(STATUS_SUCCESS,
|
||
pAspConn->aspco_ConnContext);
|
||
|
||
// Now Dereference the address object, before we are history
|
||
AtalkAspDereferenceAddr(pAspAddr);
|
||
|
||
// Finally free the memory.
|
||
AtalkFreeMemory(pAspConn);
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspSlsXHandler(
|
||
IN ATALK_ERROR ErrorCode,
|
||
IN PASP_ADDROBJ pAspAddr, // Listener (our context)
|
||
IN PATP_RESP pAtpResp, // Atp Response context
|
||
IN PATALK_ADDR pSrcAddr, // Address of requestor
|
||
IN USHORT PktLen,
|
||
IN PBYTE pPkt,
|
||
IN PBYTE pUserBytes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handler for incoming requests on the Sls. It handles session opens, tickles
|
||
and get status on the session.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn;
|
||
ATALK_ERROR Status;
|
||
PASP_POSTSTAT_CTX pStsCtx;
|
||
int index;
|
||
USHORT StsBufSize;
|
||
BYTE AspCmd, SessionId, StartId;
|
||
BOOLEAN fAddrRefed=FALSE;
|
||
|
||
|
||
if (!ATALK_SUCCESS(ErrorCode))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("atalkAspSlsXHandler: Error %ld\n", ErrorCode));
|
||
|
||
// Take away the reference on the Sls now that the atp address is closing
|
||
if (ErrorCode == ATALK_ATP_CLOSING)
|
||
AtalkAspDereferenceAddr(pAspAddr);
|
||
return;
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSlsXHandler: Entered for Function %x from %x.%x\n",
|
||
pUserBytes[ASP_CMD_OFF], pSrcAddr->ata_Network, pSrcAddr->ata_Node));
|
||
|
||
switch (AspCmd = pUserBytes[ASP_CMD_OFF])
|
||
{
|
||
case ASP_OPEN_SESSION:
|
||
// Is the version number ok ?
|
||
if ((pUserBytes[ASP_VERSION_OFF] != ASP_VERSION[0]) ||
|
||
(pUserBytes[ASP_VERSION_OFF+1] != ASP_VERSION[1]))
|
||
{
|
||
atalkAspReturnResp( pAtpResp,
|
||
pSrcAddr,
|
||
0, // SSS
|
||
0, // SessionId
|
||
ASP_BAD_VERSION); // ErrorCode
|
||
break;
|
||
}
|
||
|
||
// Create a connection object corres. to this listen and then notify
|
||
// the client that it needs to handle a new session
|
||
// Allocate memory for a connection object
|
||
if ((pAspConn = AtalkAllocZeroedMemory(sizeof(ASP_CONNOBJ))) != NULL)
|
||
{
|
||
#if DBG
|
||
pAspConn->aspco_Signature = ASPCO_SIGNATURE;
|
||
#endif
|
||
INITIALIZE_SPIN_LOCK(&pAspConn->aspco_Lock);
|
||
pAspConn->aspco_RefCount = 1; // Creation reference
|
||
pAspConn->aspco_pAspAddr = pAspAddr; // Owning address object
|
||
AtalkInitializeRT(&pAspConn->aspco_RT,
|
||
ATP_INITIAL_INTERVAL_FOR_ASP,
|
||
ATP_MIN_INTERVAL_FOR_ASP,
|
||
ATP_MAX_INTERVAL_FOR_ASP);
|
||
}
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
if (pAspConn != NULL)
|
||
{
|
||
PASP_CONNOBJ pTmp;
|
||
|
||
// Find a session id that we can use for this session. We use
|
||
// the next assignable id, if that is not in use. Otherwise we
|
||
// use the next id not in use by that session. In most cases
|
||
// we have only one session from any client.
|
||
index = HASH_SRCADDR(pSrcAddr);
|
||
|
||
// If we do not find any, we use this
|
||
SessionId = StartId = pAspAddr->aspao_NextSessionId++;
|
||
ASSERT (SessionId != 0);
|
||
if (pAspAddr->aspao_NextSessionId == 0)
|
||
pAspAddr->aspao_NextSessionId = 1;
|
||
|
||
for (pTmp = pAspAddr->aspao_pSessions[index];
|
||
pTmp != NULL;
|
||
NOTHING)
|
||
{
|
||
if ((pTmp->aspco_WssRemoteAddr.ata_Node == pSrcAddr->ata_Node) &&
|
||
(pTmp->aspco_WssRemoteAddr.ata_Network == pSrcAddr->ata_Network))
|
||
{
|
||
if (pTmp->aspco_SessionId == SessionId)
|
||
{
|
||
// if we have cycled through all, get out!
|
||
if (SessionId == (StartId - 1))
|
||
{
|
||
break;
|
||
}
|
||
|
||
SessionId ++;
|
||
if (SessionId == 0)
|
||
{
|
||
// all sessions are taken: quit here!
|
||
if (StartId == 1)
|
||
{
|
||
break;
|
||
}
|
||
SessionId = 1;
|
||
}
|
||
pTmp = pAspAddr->aspao_pSessions[index];
|
||
continue;
|
||
}
|
||
}
|
||
pTmp = pTmp->aspco_NextOverflow;
|
||
}
|
||
|
||
// if there are 255 sessions already from this address, then
|
||
// we can't have any more, sorry !!!
|
||
if (SessionId != (StartId - 1))
|
||
{
|
||
// Link it into the hash table
|
||
pAspAddr->aspao_RefCount ++;
|
||
fAddrRefed = TRUE;
|
||
|
||
pAspConn->aspco_SessionId = SessionId;
|
||
pAspConn->aspco_cReqsInProcess = 0;
|
||
pAspConn->aspco_WssRemoteAddr.ata_Address = pSrcAddr->ata_Address;
|
||
pAspConn->aspco_WssRemoteAddr.ata_Socket = pUserBytes[ASP_WSS_OFF];
|
||
pAspConn->aspco_LastContactTime = AtalkGetCurrentTick();
|
||
pAspConn->aspco_NextExpectedSeqNum = 0;
|
||
pAspConn->aspco_Flags |= (ASPCO_ACTIVE | ASPCO_TICKLING);
|
||
|
||
// The session should be linked *after* all of the above
|
||
// are initialized
|
||
pAspConn->aspco_NextOverflow = pAspAddr->aspao_pSessions[index];
|
||
pAspAddr->aspao_pSessions[index] = pAspConn;
|
||
#ifdef PROFILING
|
||
INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_CurAspSessions,
|
||
&AtalkStatsLock.SpinLock);
|
||
|
||
INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_TotalAspSessions,
|
||
&AtalkStatsLock.SpinLock);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
AtalkFreeMemory(pAspConn);
|
||
pAspConn = NULL;
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
if (pAspConn != NULL)
|
||
{
|
||
BYTE Socket;
|
||
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSlsXHandler: Opening session from %d.%d for Session %d\n",
|
||
pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
||
|
||
|
||
// Call the open completion routine and get a context. This is needed
|
||
// before we do anything else. Once we send out an open success it'll
|
||
// be too late.
|
||
// FALSE says this is not over TCP/IP
|
||
pAspConn->aspco_ConnContext =
|
||
(*pAspAddr->aspao_ClientEntries.clt_SessionNotify)(pAspConn,FALSE);
|
||
|
||
if (pAspConn->aspco_ConnContext != NULL)
|
||
{
|
||
// Now link the session into the global list
|
||
ACQUIRE_SPIN_LOCK_DPC(&atalkAspLock);
|
||
AtalkLinkDoubleAtHead(atalkAspConnMaint[SessionId & (NUM_ASP_CONN_LISTS-1)].ascm_ConnList,
|
||
pAspConn,
|
||
aspco_NextSession,
|
||
aspco_PrevSession)
|
||
RELEASE_SPIN_LOCK_DPC(&atalkAspLock);
|
||
|
||
// Send an open session response - XO
|
||
Socket = pAspAddr->aspao_pSssAtpAddr->atpao_DdpAddr->ddpao_Addr.ata_Socket;
|
||
atalkAspReturnResp( pAtpResp,
|
||
pSrcAddr,
|
||
Socket,
|
||
pAspConn->aspco_SessionId,
|
||
0); // Success
|
||
|
||
// Send a tickle out every ASP_TICKLE_INTERVAL seconds
|
||
UserBytes[ASP_CMD_OFF] = ASP_TICKLE;
|
||
UserBytes[ASP_SESSIONID_OFF] = pAspConn->aspco_SessionId;
|
||
PUTSHORT2SHORT(UserBytes + ASP_ERRORCODE_OFF, 0);
|
||
Status = AtalkAtpPostReq(pAspAddr->aspao_pSlsAtpAddr,
|
||
&pAspConn->aspco_WssRemoteAddr,
|
||
&pAspConn->aspco_TickleXactId,
|
||
ATP_REQ_REMOTE, // Tickle packets are ALO
|
||
NULL,
|
||
0,
|
||
UserBytes,
|
||
NULL,
|
||
0,
|
||
ATP_INFINITE_RETRIES,
|
||
ASP_TICKLE_INTERVAL,
|
||
THIRTY_SEC_TIMER,
|
||
NULL,
|
||
NULL);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
pAspConn->aspco_Flags &= ~ASPCO_TICKLING;
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSlsXHandler: AtalkAtpPostReq %ld\n", Status));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PASP_CONNOBJ * ppAspConn;
|
||
|
||
// Unlink it from the hash table
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
for (ppAspConn = &pAspAddr->aspao_pSessions[index];
|
||
*ppAspConn != NULL;
|
||
ppAspConn = &(*ppAspConn)->aspco_NextOverflow)
|
||
{
|
||
if (*ppAspConn == pAspConn)
|
||
{
|
||
*ppAspConn = pAspConn->aspco_NextOverflow;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT (*ppAspConn == pAspConn->aspco_NextOverflow);
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
AtalkFreeMemory(pAspConn);
|
||
pAspConn = NULL;
|
||
#ifdef PROFILING
|
||
INTERLOCKED_DECREMENT_LONG_DPC(&AtalkStatistics.stat_CurAspSessions,
|
||
&AtalkStatsLock.SpinLock);
|
||
|
||
INTERLOCKED_DECREMENT_LONG_DPC(&AtalkStatistics.stat_TotalAspSessions,
|
||
&AtalkStatsLock.SpinLock);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
// If we are set to disable listens or could not allocate memory, drop it
|
||
if (pAspConn == NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSlsXHandler: No conn objects available\n"));
|
||
|
||
atalkAspReturnResp( pAtpResp,
|
||
pSrcAddr,
|
||
0,
|
||
0,
|
||
ASP_SERVER_BUSY);
|
||
|
||
// remove that refcount if we put it in hoping afp would accept the request
|
||
if (fAddrRefed)
|
||
{
|
||
AtalkAspDereferenceAddr(pAspAddr);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case ASP_GET_STATUS:
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSssXHandler: Received GetStat from %x.%x\n",
|
||
pSrcAddr->ata_Network, pSrcAddr->ata_Node));
|
||
// Create an Mdl to describe the status buffer and post a response
|
||
// to the GetStatus request
|
||
StsBufSize = 0;
|
||
pStsCtx = NULL;
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
if (pAspAddr->aspao_pStatusBuf != NULL)
|
||
{
|
||
pStsCtx = (PASP_POSTSTAT_CTX)AtalkAllocMemory(sizeof(ASP_POSTSTAT_CTX) +
|
||
pAspAddr->aspao_StsBufSize);
|
||
if (pStsCtx != NULL)
|
||
{
|
||
pStsCtx->aps_pAMdl = AtalkAllocAMdl((PBYTE)pStsCtx + sizeof(ASP_POSTSTAT_CTX),
|
||
pAspAddr->aspao_StsBufSize);
|
||
if (pStsCtx->aps_pAMdl != NULL)
|
||
{
|
||
pStsCtx->aps_pAtpResp = pAtpResp;
|
||
StsBufSize = pAspAddr->aspao_StsBufSize;
|
||
RtlCopyMemory((PBYTE)pStsCtx + sizeof(ASP_POSTSTAT_CTX),
|
||
pAspAddr->aspao_pStatusBuf,
|
||
StsBufSize);
|
||
}
|
||
else
|
||
{
|
||
AtalkFreeMemory(pStsCtx);
|
||
pStsCtx = NULL;
|
||
StsBufSize = 0;
|
||
}
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pAspAddr->aspao_Lock);
|
||
|
||
Status = AtalkAtpPostResp(pAtpResp,
|
||
pSrcAddr,
|
||
(pStsCtx != NULL) ?
|
||
pStsCtx->aps_pAMdl : NULL,
|
||
StsBufSize,
|
||
NULL,
|
||
atalkAspRespComplete,
|
||
pStsCtx);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSlsXHandler: AtalkAtpPostResp %ld\n", Status));
|
||
atalkAspRespComplete(Status, pStsCtx);
|
||
}
|
||
break;
|
||
|
||
case ASP_TICKLE:
|
||
SessionId = pUserBytes[ASP_SESSIONID_OFF];
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSssXHandler: Received tickle from %x.%x Session %d\n",
|
||
pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
||
|
||
if ((pAspConn = atalkAspReferenceConnBySrcAddr(pAspAddr, pSrcAddr, SessionId)) != NULL)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
pAspConn->aspco_LastContactTime = AtalkGetCurrentTick();
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: Conn not found for addr %d.%d Session %d\n",
|
||
pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
||
}
|
||
// Fall through to the default case
|
||
|
||
default:
|
||
// Cancel this response since we never respond to it and we want this to go away
|
||
AtalkAtpCancelResp(pAtpResp);
|
||
|
||
if (AspCmd != ASP_TICKLE)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSlsXHandler: Invalid command\n"));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspSssXHandler(
|
||
IN ATALK_ERROR ErrorCode,
|
||
IN PASP_ADDROBJ pAspAddr, // Listener (our context)
|
||
IN PATP_RESP pAtpResp, // Atp Response context
|
||
IN PATALK_ADDR pSrcAddr, // Address of requestor
|
||
IN USHORT PktLen,
|
||
IN PBYTE pPkt,
|
||
IN PBYTE pUserBytes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handler for incoming requests on the Sss. It handles incoming requests, close
|
||
and write continue.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn; // Session which will handle this request
|
||
PASP_REQUEST pAspReq; // The request that will be satisfied
|
||
ATALK_ERROR Status;
|
||
NTSTATUS retStatus;
|
||
USHORT SequenceNum; // From the incoming packet
|
||
BYTE SessionId; // -- ditto --
|
||
BYTE RequestType; // -- ditto --
|
||
BOOLEAN CancelResp = FALSE,
|
||
CancelTickle;
|
||
BOOLEAN fTellAfp=TRUE;
|
||
|
||
do
|
||
{
|
||
if (!ATALK_SUCCESS(ErrorCode))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("atalkAspSssXHandler: Error %ld\n", ErrorCode));
|
||
// Take away the reference on the Sls now that the atp address is closing
|
||
if (ErrorCode == ATALK_ATP_CLOSING)
|
||
AtalkAspDereferenceAddr(pAspAddr);
|
||
break;
|
||
}
|
||
|
||
// Get the session id out of the packet and reference the session that this
|
||
// request is targeted to.
|
||
SessionId = pUserBytes[ASP_SESSIONID_OFF];
|
||
RequestType = pUserBytes[ASP_CMD_OFF];
|
||
GETSHORT2SHORT(&SequenceNum, pUserBytes+ASP_SEQUENCE_NUM_OFF);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSssXHandler: Entered for Request %x from %x.%x\n",
|
||
RequestType, pSrcAddr->ata_Network, pSrcAddr->ata_Node));
|
||
|
||
// The reference for this connection is passed down to the request
|
||
// for the ASP_CMD & ASP_WRITE case.
|
||
pAspConn = atalkAspReferenceConnBySrcAddr(pAspAddr, pSrcAddr, SessionId);
|
||
if (pAspConn == NULL)
|
||
{
|
||
CancelResp = TRUE;
|
||
break;
|
||
}
|
||
|
||
ASSERT (pAspConn->aspco_pAspAddr == pAspAddr);
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
pAspConn->aspco_LastContactTime = AtalkGetCurrentTick();
|
||
|
||
switch (RequestType)
|
||
{
|
||
case ASP_CMD:
|
||
case ASP_WRITE:
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSssXHandler: %s\n",
|
||
(RequestType == ASP_CMD) ? "Command" : "Write"));
|
||
// Create a request for this and notify the client to handle this
|
||
// Validate the incoming sequence number. Reject if out of sequence
|
||
if (SequenceNum == pAspConn->aspco_NextExpectedSeqNum)
|
||
{
|
||
// We now have a request to be handled.
|
||
// The reference to the connection above will be passed on
|
||
// to the request. This will get de-referenced when the
|
||
// request is replied to. See if we have a free request to pick up
|
||
// Allocate a request structure if not and link it in the listener object
|
||
if ((pAspReq = pAspConn->aspco_pFreeReqs) != NULL)
|
||
pAspConn->aspco_pFreeReqs = pAspReq->asprq_Next;
|
||
else pAspReq = AtalkBPAllocBlock(BLKID_ASPREQ);
|
||
|
||
if (pAspReq != NULL)
|
||
{
|
||
pAspConn->aspco_NextExpectedSeqNum ++;
|
||
#if DBG
|
||
pAspReq->asprq_Signature = ASPRQ_SIGNATURE;
|
||
#endif
|
||
pAspReq->asprq_pAtpResp = pAtpResp;
|
||
pAspReq->asprq_pAspConn = pAspConn;
|
||
pAspReq->asprq_ReqType = RequestType;
|
||
pAspReq->asprq_SeqNum = SequenceNum;
|
||
pAspReq->asprq_RemoteAddr = *pSrcAddr;
|
||
pAspReq->asprq_Flags = 0;
|
||
pAspReq->asprq_Request.rq_WriteMdl = NULL;
|
||
pAspReq->asprq_Request.rq_CacheMgrContext = NULL;
|
||
pAspReq->asprq_Request.rq_RequestSize = PktLen;
|
||
pAspReq->asprq_Next = pAspConn->aspco_pActiveReqs;
|
||
pAspConn->aspco_cReqsInProcess ++;
|
||
pAspConn->aspco_pActiveReqs = pAspReq;
|
||
|
||
ASSERT ((pAspConn->aspco_Flags & (ASPCO_CLEANING_UP |
|
||
ASPCO_CLOSING |
|
||
ASPCO_LOCAL_CLOSE |
|
||
ASPCO_REMOTE_CLOSE)) == 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pAspReq = NULL;
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: Sequence mismatch exp %x, act %x\n",
|
||
pAspConn->aspco_NextExpectedSeqNum, SequenceNum));
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
// If we do not have an request to handle this, cancel the
|
||
// response. Otherwise the client will keep retrying and atp
|
||
// will not tell us since it already has.
|
||
if (pAspReq == NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: Dropping request for session %d from %d.%d\n",
|
||
SessionId, pSrcAddr->ata_Network, pSrcAddr->ata_Node));
|
||
|
||
CancelResp = TRUE;
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
break;
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSssXHandler: Indicating Request %lx\n", pAspReq));
|
||
|
||
if (RequestType == ASP_WRITE)
|
||
{
|
||
if (PktLen > MAX_WRITE_REQ_SIZE)
|
||
{
|
||
PASP_REQUEST *ppTmpAspReq;
|
||
|
||
ASSERT(0);
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
for (ppTmpAspReq = &pAspConn->aspco_pActiveReqs;
|
||
*ppTmpAspReq != NULL; ppTmpAspReq = &(*ppTmpAspReq)->asprq_Next )
|
||
{
|
||
if (pAspReq == *ppTmpAspReq)
|
||
{
|
||
*ppTmpAspReq = pAspReq->asprq_Next;
|
||
break;
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
AtalkBPFreeBlock(pAspReq);
|
||
pAspReq = NULL;
|
||
CancelResp = TRUE;
|
||
break;
|
||
}
|
||
|
||
RtlCopyMemory(pAspReq->asprq_ReqBuf, pPkt, PktLen);
|
||
pAspReq->asprq_Request.rq_RequestBuf = pAspReq->asprq_ReqBuf;
|
||
|
||
retStatus = (*pAspAddr->aspao_ClientEntries.clt_GetWriteBuffer)
|
||
(pAspConn->aspco_ConnContext,&pAspReq->asprq_Request);
|
||
|
||
//
|
||
// most common case: file server will pend it so it can go to cache mgr
|
||
//
|
||
if (retStatus == STATUS_PENDING)
|
||
{
|
||
fTellAfp = FALSE;
|
||
break;
|
||
}
|
||
else if (retStatus == STATUS_SUCCESS)
|
||
{
|
||
if (pAspReq->asprq_Request.rq_WriteMdl != NULL)
|
||
{
|
||
atalkAspPostWriteContinue(pAspReq);
|
||
|
||
// we informed (or will inform) AFP about this request: don't
|
||
// inform again below!
|
||
fTellAfp = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: GetWriteBuffer returned %lx on %lx\n",
|
||
retStatus,pAspConn));
|
||
}
|
||
}
|
||
|
||
// TRUE for CMD as well
|
||
if ((pAspReq->asprq_Request.rq_WriteMdl == NULL) &&
|
||
(fTellAfp))
|
||
{
|
||
pAspReq->asprq_Request.rq_RequestBuf = pPkt;
|
||
|
||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||
|
||
// Notify the client that it has a request to handle
|
||
retStatus = (*pAspAddr->aspao_ClientEntries.clt_RequestNotify)
|
||
(STATUS_SUCCESS,
|
||
pAspConn->aspco_ConnContext,
|
||
&pAspReq->asprq_Request);
|
||
|
||
if (!NT_SUCCESS(retStatus))
|
||
{
|
||
PASP_REQUEST *ppTmpAspReq;
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: Afp didn't accept request %lx on conn %lx\n",
|
||
pAspReq,pAspConn));
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
for (ppTmpAspReq = &pAspConn->aspco_pActiveReqs;
|
||
*ppTmpAspReq != NULL; ppTmpAspReq = &(*ppTmpAspReq)->asprq_Next )
|
||
{
|
||
if (pAspReq == *ppTmpAspReq)
|
||
{
|
||
*ppTmpAspReq = pAspReq->asprq_Next;
|
||
break;
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
AtalkBPFreeBlock(pAspReq);
|
||
pAspReq = NULL;
|
||
CancelResp = TRUE;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case ASP_CLOSE_SESSION:
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("atalkAspSssXHandler: Close request from %d.%d for Session %d\n",
|
||
pSrcAddr->ata_Network, pSrcAddr->ata_Node, SessionId));
|
||
|
||
#ifdef PROFILING
|
||
INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_AspSessionsClosed,
|
||
&AtalkStatsLock.SpinLock);
|
||
#endif
|
||
|
||
CancelTickle = ((pAspConn->aspco_Flags &ASPCO_TICKLING) != 0);
|
||
pAspConn->aspco_Flags &= ~(ASPCO_ACTIVE | ASPCO_TICKLING);
|
||
pAspConn->aspco_Flags |= ASPCO_REMOTE_CLOSE;
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
// Send a CloseSession reply and close the session
|
||
Status = AtalkAtpPostResp(pAtpResp,
|
||
pSrcAddr,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
AtalkAtpGenericRespComplete,
|
||
pAtpResp);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
AtalkAtpGenericRespComplete(Status, pAtpResp);
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: AtalkAtpPostResp failed %ld\n", Status));
|
||
}
|
||
|
||
// Cancel the tickle requests for this session
|
||
if (CancelTickle)
|
||
{
|
||
Status = AtalkAtpCancelReq(pAspAddr->aspao_pSlsAtpAddr,
|
||
pAspConn->aspco_TickleXactId,
|
||
&pAspConn->aspco_WssRemoteAddr);
|
||
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: AtalkAtpCancelReq %ld\n", Status));
|
||
}
|
||
}
|
||
|
||
// Shut down this session, well almost ... Note that we have a reference
|
||
// to this connection which will be Dereferenced by atalkAspSessionClose.
|
||
atalkAspSessionClose(pAspConn);
|
||
break;
|
||
|
||
default:
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
CancelResp = TRUE;
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: Invalid command %d\n", RequestType));
|
||
break;
|
||
}
|
||
} while (FALSE);
|
||
|
||
if (CancelResp)
|
||
{
|
||
Status = AtalkAtpCancelResp(pAtpResp);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_ERR,
|
||
("atalkAspSssXHandler: AtalkAspCancelResp %ld\n", Status));
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID FASTCALL
|
||
atalkAspReplyRelease(
|
||
IN ATALK_ERROR ErrorCode,
|
||
IN PASP_REQUEST pAspReq
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handler for incoming release for reply
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn;
|
||
PASP_ADDROBJ pAspAddr;
|
||
KIRQL OldIrql;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
ASSERT (VALID_ASPRQ(pAspReq));
|
||
pAspConn = pAspReq->asprq_pAspConn;
|
||
ASSERT (VALID_ASPCO(pAspConn));
|
||
|
||
pAspAddr = pAspConn->aspco_pAspAddr;
|
||
ASSERT (VALID_ASPAO(pAspAddr));
|
||
|
||
ASSERT ((pAspReq->asprq_Flags & ASPRQ_REPLY) || !ATALK_SUCCESS(ErrorCode));
|
||
|
||
if (!NT_SUCCESS(ErrorCode))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("atalkAspReplyRelease: Failure %ld\n", ErrorCode));
|
||
Status = AtalkErrorToNtStatus(ErrorCode);
|
||
}
|
||
|
||
// We complete here
|
||
(*pAspAddr->aspao_ClientEntries.clt_ReplyCompletion)(Status,
|
||
pAspConn->aspco_ConnContext,
|
||
&pAspReq->asprq_Request);
|
||
|
||
// Based on whether a reply was actually sent or not, either deref the response
|
||
// or cancel it.
|
||
if (pAspReq->asprq_Flags & ASPRQ_REPLY)
|
||
{
|
||
AtalkAtpRespDereference(pAspReq->asprq_pAtpResp);
|
||
}
|
||
else
|
||
{
|
||
AtalkAtpCancelResp(pAspReq->asprq_pAtpResp);
|
||
}
|
||
|
||
// make sure we aren't hanging on to cache mgr's mdl!
|
||
ASSERT(pAspReq->asprq_Request.rq_CacheMgrContext == NULL);
|
||
|
||
#if DBG
|
||
pAspReq->asprq_Signature = 0x28041998;
|
||
pAspReq->asprq_pAtpResp = (PATP_RESP)(pAspReq->asprq_Request.rq_WriteMdl);
|
||
pAspReq->asprq_pAspConn = (PASP_CONNOBJ)(pAspReq->asprq_Request.rq_CacheMgrContext);
|
||
pAspReq->asprq_Request.rq_WriteMdl = (PMDL)0x44556677;
|
||
pAspReq->asprq_Request.rq_CacheMgrContext = (PVOID)66778899;
|
||
#endif
|
||
|
||
|
||
// Free this as we are done with this request now
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
|
||
if (pAspConn->aspco_pFreeReqs == NULL)
|
||
{
|
||
pAspReq->asprq_Next = NULL;
|
||
pAspConn->aspco_pFreeReqs = pAspReq;
|
||
}
|
||
else AtalkBPFreeBlock(pAspReq);
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
// We are done with this request.
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspWriteContinueResp(
|
||
IN ATALK_ERROR ErrorCode,
|
||
IN PASP_REQUEST pAspReq,
|
||
IN PAMDL pReqAMdl,
|
||
IN PAMDL pRespAMdl,
|
||
IN USHORT RespSize,
|
||
IN PBYTE RespUserBytes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handler for incoming write continue response.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn;
|
||
PASP_ADDROBJ pAspAddr;
|
||
NTSTATUS Status;
|
||
NTSTATUS retStatus;
|
||
KIRQL OldIrql;
|
||
PASP_REQUEST * ppAspReq;
|
||
PVOID pClientContxt;
|
||
|
||
|
||
ASSERT (VALID_ASPRQ(pAspReq));
|
||
|
||
ASSERT(pAspReq->asprq_Flags & ASPRQ_WRTCONT);
|
||
|
||
pAspConn = pAspReq->asprq_pAspConn;
|
||
ASSERT(VALID_ASPCO(pAspConn));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspWriteContinueResp: Entered for request %lx\n", pAspReq));
|
||
|
||
pAspAddr = pAspConn->aspco_pAspAddr;
|
||
ASSERT(VALID_ASPAO(pAspAddr));
|
||
|
||
pAspReq->asprq_Flags &= ~ASPRQ_WRTCONT;
|
||
|
||
pClientContxt = pAspConn->aspco_ConnContext;
|
||
|
||
if (ATALK_SUCCESS(ErrorCode))
|
||
{
|
||
pAspConn->aspco_RT.rt_New = AtalkGetCurrentTick() - pAspConn->aspco_RT.rt_New;
|
||
|
||
// Estimate the retry interval for next time.
|
||
AtalkCalculateNewRT(&pAspConn->aspco_RT);
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
Status = AtalkErrorToNtStatus(ErrorCode);
|
||
}
|
||
|
||
#ifdef PROFILING
|
||
{
|
||
KIRQL OldIrql;
|
||
|
||
ACQUIRE_SPIN_LOCK(&AtalkStatsLock, &OldIrql);
|
||
|
||
AtalkStatistics.stat_LastAspRTT = (ULONG)(pAspConn->aspco_RT.rt_Base);
|
||
if ((ULONG)(pAspConn->aspco_RT.rt_Base) > AtalkStatistics.stat_MaxAspRTT)
|
||
AtalkStatistics.stat_MaxAspRTT = (ULONG)(pAspConn->aspco_RT.rt_Base);
|
||
|
||
RELEASE_SPIN_LOCK(&AtalkStatsLock, OldIrql);
|
||
}
|
||
#endif
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspWriteContinueResp: Indicating request %lx\n", pAspReq));
|
||
|
||
// Notify the client that it has a request to handle
|
||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
|
||
retStatus = (*pAspAddr->aspao_ClientEntries.clt_RequestNotify)
|
||
(Status,
|
||
pClientContxt,
|
||
&pAspReq->asprq_Request);
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
//
|
||
// In case the writecontinue returned an error, this request needs to go away
|
||
// since there will never be a call to AtalkAspReply(). Also deref the conn.
|
||
// Alternately, if the response came in fine, but the server didn't want to accept
|
||
// it, it's the same deal
|
||
//
|
||
if ( (!NT_SUCCESS(Status)) || (!NT_SUCCESS(retStatus)) )
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspWriteContinueResp: incoming %lx, Afp %lx req: %lx on %lx, cancelling\n",
|
||
Status,retStatus,pAspReq,pAspConn));
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
|
||
for (ppAspReq = &pAspConn->aspco_pActiveReqs;
|
||
*ppAspReq != NULL;
|
||
ppAspReq = &(*ppAspReq)->asprq_Next)
|
||
{
|
||
if (pAspReq == *ppAspReq)
|
||
{
|
||
*ppAspReq = pAspReq->asprq_Next;
|
||
pAspConn->aspco_cReqsInProcess --;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT (*ppAspReq == pAspReq->asprq_Next);
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
|
||
// Cancel the response for the original request that caused wrtcont to be posted
|
||
AtalkAtpCancelResp(pAspReq->asprq_pAtpResp);
|
||
|
||
// Free this request as well
|
||
AtalkBPFreeBlock(pAspReq);
|
||
}
|
||
|
||
|
||
if (pReqAMdl)
|
||
{
|
||
ASSERT (AtalkGetAddressFromMdlSafe(pReqAMdl, NormalPagePriority) == pAspReq->asprq_WrtContRespBuf);
|
||
ASSERT (AtalkSizeMdlChain(pReqAMdl) == ASP_WRITE_DATA_SIZE);
|
||
|
||
AtalkFreeAMdl(pReqAMdl);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspSendAttentionResp(
|
||
IN ATALK_ERROR ErrorCode,
|
||
IN PVOID pContext,
|
||
IN PAMDL pReqAMdl,
|
||
IN PAMDL pRespAMdl,
|
||
IN USHORT RespSize,
|
||
IN PBYTE RespUserBytes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handler for incoming write continue response.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PBYTE pBuf;
|
||
PASP_CONNOBJ pAspConn = (PASP_CONNOBJ)pContext;
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSendAttentionResp: Entered for conn %lx\n", pAspConn));
|
||
|
||
if (!ATALK_SUCCESS(ErrorCode))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSendAttentionResp: Failure %ld\n", ErrorCode));
|
||
}
|
||
|
||
if (pRespAMdl != NULL)
|
||
{
|
||
pBuf = AtalkGetAddressFromMdlSafe(
|
||
pRespAMdl,
|
||
NormalPagePriority);
|
||
|
||
if (pBuf != NULL)
|
||
{
|
||
AtalkFreeMemory(pBuf);
|
||
}
|
||
AtalkFreeAMdl(pRespAMdl);
|
||
}
|
||
|
||
// Call the completion routine
|
||
(*pAspConn->aspco_pAspAddr->aspao_ClientEntries.clt_AttnCompletion)(pAspConn->aspco_AttentionContext);
|
||
|
||
pAspConn->aspco_AttentionContext = NULL;
|
||
|
||
// Finally Dereference the connection
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
}
|
||
|
||
|
||
|
||
LOCAL LONG FASTCALL
|
||
atalkAspSessionMaintenanceTimer(
|
||
IN PTIMERLIST pTimer,
|
||
IN BOOLEAN TimerShuttingDown
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_CONNOBJ pAspConn, pAspConnNext;
|
||
PASP_CONN_MAINT pAspCM;
|
||
BOOLEAN Close = FALSE;
|
||
LONG CurrentTick = AtalkGetCurrentTick();
|
||
#ifdef PROFILING
|
||
TIME TimeS, TimeE, TimeD;
|
||
|
||
TimeS = KeQueryPerformanceCounter(NULL);
|
||
#endif
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSessionMaintenanceTimer: Entered\n"));
|
||
|
||
if (TimerShuttingDown)
|
||
return ATALK_TIMER_NO_REQUEUE;
|
||
|
||
pAspCM = CONTAINING_RECORD(pTimer, ASP_CONN_MAINT, ascm_SMTTimer);
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&atalkAspLock);
|
||
|
||
// Walk the list of sessions on the global list and shut down
|
||
// sessions that have not tickle'd for a while
|
||
for (pAspConn = pAspCM->ascm_ConnList; pAspConn != NULL; pAspConn = pAspConnNext)
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspSessionMaintenanceTimer: Checking out session %d from %x.%x\n",
|
||
pAspConn->aspco_SessionId,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Network,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Node));
|
||
|
||
pAspConnNext = pAspConn->aspco_NextSession;
|
||
|
||
Close = FALSE;
|
||
ASSERT (VALID_ASPCO(pAspConn));
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
if ((pAspConn->aspco_Flags & ASPCO_ACTIVE) &&
|
||
((CurrentTick - pAspConn->aspco_LastContactTime) > ASP_MAX_SESSION_IDLE_TIME))
|
||
{
|
||
pAspConn->aspco_Flags |= (ASPCO_REMOTE_CLOSE | ASPCO_DROPPED);
|
||
pAspConn->aspco_Flags &= ~ASPCO_ACTIVE;
|
||
pAspConn->aspco_RefCount ++; // Since atalkAspSessionClose Derefs it
|
||
|
||
Close = TRUE;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAspConn->aspco_Lock);
|
||
|
||
if (Close)
|
||
{
|
||
PASP_ADDROBJ pAspAddr;
|
||
ATALK_ERROR Status;
|
||
|
||
#ifdef PROFILING
|
||
INTERLOCKED_INCREMENT_LONG_DPC(&AtalkStatistics.stat_AspSessionsDropped,
|
||
&AtalkStatsLock.SpinLock);
|
||
#endif
|
||
pAspAddr = pAspConn->aspco_pAspAddr;
|
||
ASSERT (VALID_ASPAO(pAspAddr));
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSessionMaintenanceTimer: Shutting down session %d from %x.%x\n",
|
||
pAspConn->aspco_SessionId,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Network,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Node));
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&atalkAspLock);
|
||
|
||
// This session is being punted. Cancel tickles on this and notify the
|
||
// server that this session is history.
|
||
Status = AtalkAtpCancelReq(pAspAddr->aspao_pSlsAtpAddr,
|
||
pAspConn->aspco_TickleXactId,
|
||
&pAspConn->aspco_WssRemoteAddr);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspSessionMaintenanceTimer: AtalkAtpCancelReq %ld\n", Status));
|
||
}
|
||
|
||
// Shut down this session, well almost ...
|
||
atalkAspSessionClose(pAspConn);
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&atalkAspLock);
|
||
pAspConnNext = pAspCM->ascm_ConnList;
|
||
}
|
||
}
|
||
|
||
#ifdef PROFILING
|
||
TimeE = KeQueryPerformanceCounter(NULL);
|
||
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
|
||
|
||
INTERLOCKED_ADD_LARGE_INTGR_DPC(&AtalkStatistics.stat_AspSmtProcessTime,
|
||
TimeD,
|
||
&AtalkStatsLock.SpinLock);
|
||
|
||
INTERLOCKED_INCREMENT_LONG_DPC( &AtalkStatistics.stat_AspSmtCount,
|
||
&AtalkStatsLock.SpinLock);
|
||
#endif
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&atalkAspLock);
|
||
|
||
// Reschedule ourselves
|
||
return ATALK_TIMER_REQUEUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspSessionClose(
|
||
IN PASP_CONNOBJ pAspConn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This should be called with a reference to the connection which is Dereferenced
|
||
here.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PASP_REQUEST pAspReq, pAspReqNext;
|
||
PASP_ADDROBJ pAspAddr = pAspConn->aspco_pAspAddr;
|
||
REQUEST Request;
|
||
KIRQL OldIrql;
|
||
NTSTATUS Status = STATUS_REMOTE_DISCONNECT;
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
pAspConn->aspco_Flags &= ~ASPCO_ACTIVE;
|
||
|
||
// Cancel any Write-continues pending. Do not bother cancelling
|
||
// replies as they will time out anyway. Also atalkAspReplyRelease()
|
||
// will attempt to acquire the connection lock and we're already
|
||
// holding it
|
||
for (pAspReq = pAspConn->aspco_pActiveReqs;
|
||
pAspReq != NULL;
|
||
pAspReq = pAspReqNext)
|
||
{
|
||
pAspReqNext = pAspReq->asprq_Next;
|
||
if ((pAspReq->asprq_Flags & (ASPRQ_WRTCONT | ASPRQ_WRTCONT_CANCELLED)) == ASPRQ_WRTCONT)
|
||
{
|
||
pAspReq->asprq_Flags |= ASPRQ_WRTCONT_CANCELLED;
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
AtalkAtpCancelReq(pAspAddr->aspao_pSssAtpAddr,
|
||
pAspReq->asprq_WCXactId,
|
||
&pAspConn->aspco_WssRemoteAddr);
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAspConn->aspco_Lock, &OldIrql);
|
||
pAspReqNext = pAspConn->aspco_pActiveReqs;
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAspConn->aspco_Lock, OldIrql);
|
||
|
||
if (pAspConn->aspco_Flags & ASPCO_DROPPED)
|
||
{
|
||
Status = STATUS_LOCAL_DISCONNECT;
|
||
}
|
||
|
||
// Indicate a request with an error to indicate that the session closed remotely.
|
||
// Pass the remote address of the client so that the server can log an event if
|
||
// the session did not shutdown gracefully.
|
||
|
||
Request.rq_RequestSize = (LONG)(pAspConn->aspco_WssRemoteAddr.ata_Address);
|
||
Request.rq_RequestBuf = NULL;
|
||
Request.rq_WriteMdl = NULL;
|
||
Request.rq_CacheMgrContext = NULL;
|
||
|
||
(*pAspAddr->aspao_ClientEntries.clt_RequestNotify)(Status,
|
||
pAspConn->aspco_ConnContext,
|
||
&Request);
|
||
// Finally Dereference the session
|
||
AtalkAspDereferenceConn(pAspConn);
|
||
}
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspReturnResp(
|
||
IN PATP_RESP pAtpResp,
|
||
IN PATALK_ADDR pDstAddr,
|
||
IN BYTE Byte0,
|
||
IN BYTE Byte1,
|
||
IN USHORT Word2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
BYTE UserBytes[ATP_USERBYTES_SIZE];
|
||
ATALK_ERROR Status;
|
||
|
||
UserBytes[0] = Byte0;
|
||
UserBytes[1] = Byte1;
|
||
PUTSHORT2SHORT(UserBytes+2, Word2);
|
||
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspReturnResp: For Resp %lx\n", pAtpResp));
|
||
|
||
Status = AtalkAtpPostResp(pAtpResp,
|
||
pDstAddr,
|
||
NULL,
|
||
0,
|
||
UserBytes,
|
||
AtalkAtpGenericRespComplete,
|
||
pAtpResp);
|
||
if (!ATALK_SUCCESS(Status))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspReturnResp: AtalkAtpPostResp failed %ld\n", Status));
|
||
AtalkAtpGenericRespComplete(Status, pAtpResp);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID FASTCALL
|
||
atalkAspRespComplete(
|
||
IN ATALK_ERROR ErrorCode,
|
||
IN PASP_POSTSTAT_CTX pStsCtx
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
|
||
("atalkAspRespComplete: Entered pStsCtx %lx\n", pStsCtx));
|
||
|
||
if (!ATALK_SUCCESS(ErrorCode))
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_ERR,
|
||
("atalkAspRespComplete: Failed %ld, pStsCtx %lx\n", ErrorCode, pStsCtx));
|
||
}
|
||
|
||
if (pStsCtx != NULL)
|
||
{
|
||
AtalkFreeAMdl(pStsCtx->aps_pAMdl);
|
||
AtalkAtpRespDereferenceDpc(pStsCtx->aps_pAtpResp);
|
||
AtalkFreeMemory(pStsCtx);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAspCloseComplete(
|
||
IN ATALK_ERROR Status,
|
||
IN PASP_ADDROBJ pAspAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_WARN,
|
||
("atalkAspCloseComplete: AtalkAtpCloseAddr returned %ld\n", Status));
|
||
AtalkAspDereferenceAddr(pAspAddr);
|
||
}
|
||
|
||
|
||
#if DBG
|
||
|
||
VOID
|
||
AtalkAspDumpSessions(
|
||
VOID
|
||
)
|
||
{
|
||
PASP_CONNOBJ pAspConn;
|
||
KIRQL OldIrql;
|
||
LONG i;
|
||
|
||
DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL, ("ASP SESSION LIST:\n"));
|
||
|
||
ACQUIRE_SPIN_LOCK(&atalkAspLock, &OldIrql);
|
||
|
||
for (i = 0; i < NUM_ASP_CONN_LISTS; i++)
|
||
{
|
||
for (pAspConn = atalkAspConnMaint[i].ascm_ConnList;
|
||
pAspConn != NULL;
|
||
pAspConn = pAspConn->aspco_NextSession)
|
||
{
|
||
DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
|
||
("\tRemote Addr %4d.%3d.%2d SessionId %2d Flags %4x RefCount %ld\n",
|
||
pAspConn->aspco_WssRemoteAddr.ata_Network,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Node,
|
||
pAspConn->aspco_WssRemoteAddr.ata_Socket,
|
||
pAspConn->aspco_SessionId,
|
||
pAspConn->aspco_Flags,
|
||
pAspConn->aspco_RefCount));
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK(&atalkAspLock, OldIrql);
|
||
}
|
||
|
||
#endif
|
||
|
||
|