windows-nt/Source/XPSP1/NT/net/sfm/atalk/sys/atkact.c
2020-09-26 16:20:57 +08:00

730 lines
17 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
atkact.c
Abstract:
This module contains the TDI action support code.
Author:
Jameel Hyder (jameelh@microsoft.com)
Nikhil Kamkolkar (nikhilk@microsoft.com)
Revision History:
19 Jun 1992 Initial Version
Notes: Tab stop: 4
--*/
#include <atalk.h>
#pragma hdrstop
#define FILENUM ATKACT
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE_NZ, AtalkNbpTdiAction)
#pragma alloc_text(PAGE_NZ, AtalkZipTdiAction)
#pragma alloc_text(PAGE, AtalkAspTdiAction)
#pragma alloc_text(PAGE, AtalkAdspTdiAction)
#pragma alloc_text(PAGE_PAP, AtalkPapTdiAction)
#pragma alloc_text(PAGEASPC, AtalkAspCTdiAction)
#endif
ATALK_ERROR
AtalkStatTdiAction(
IN PVOID pObject, // Address or Connection object
IN struct _ActionReq * pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for Statistics TdiAction call. There are no input parameters.
The statistics structure is returned.
Arguments:
Return Value:
--*/
{
ATALK_ERROR Error = ATALK_NO_ERROR;
PPORT_DESCRIPTOR pPortDesc;
KIRQL OldIrql;
ULONG BytesCopied;
LONG Offset;
if (pActReq->ar_MdlSize < (SHORT)(sizeof(ATALK_STATS) +
sizeof(ATALK_PORT_STATS) * AtalkNumberOfPorts))
Error = ATALK_BUFFER_TOO_SMALL;
else
{
#ifdef PROFILING
// This is the only place where this is changed. And it always increases.
// Also the stats are changed using ExInterlocked calls. Acquiring a lock
// does little in terms of protection anyways.
AtalkStatistics.stat_ElapsedTime = AtalkTimerCurrentTick/ATALK_TIMER_FACTOR;
#endif
TdiCopyBufferToMdl(&AtalkStatistics,
0,
sizeof(ATALK_STATS),
pActReq->ar_pAMdl,
0,
&BytesCopied);
ASSERT(BytesCopied == sizeof(ATALK_STATS));
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
for (pPortDesc = AtalkPortList, Offset = sizeof(ATALK_STATS);
pPortDesc != NULL;
pPortDesc = pPortDesc->pd_Next)
{
TdiCopyBufferToMdl(&pPortDesc->pd_PortStats,
0,
sizeof(ATALK_PORT_STATS),
pActReq->ar_pAMdl,
Offset,
&BytesCopied);
Offset += sizeof(ATALK_PORT_STATS);
ASSERT(BytesCopied == sizeof(ATALK_PORT_STATS));
}
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
}
(*pActReq->ar_Completion)(Error, pActReq);
return ATALK_PENDING;
}
ATALK_ERROR
AtalkNbpTdiAction(
IN PVOID pObject, // Address or Connection object
IN PACTREQ pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for NBP TdiAction calls. The parameters are validated and
the calls are dispacthed to the appropriate NBP routines.
Arguments:
Return Value:
--*/
{
ATALK_ERROR error = ATALK_NO_ERROR;
PDDP_ADDROBJ pDdpAddr;
PNBPTUPLE pNbpTuple;
PAGED_CODE ();
// Lock the Nbp stuff, if this is the first nbp action
AtalkLockNbpIfNecessary();
ASSERT (VALID_ACTREQ(pActReq));
// First get the Ddp address out of the pObject for the device
switch (pActReq->ar_DevType)
{
case ATALK_DEV_DDP:
pDdpAddr = (PDDP_ADDROBJ)pObject;
break;
case ATALK_DEV_ASPC:
pDdpAddr = AtalkAspCGetDdpAddress((PASPC_ADDROBJ)pObject);
break;
case ATALK_DEV_ASP:
pDdpAddr = AtalkAspGetDdpAddress((PASP_ADDROBJ)pObject);
break;
case ATALK_DEV_PAP:
pDdpAddr = AtalkPapGetDdpAddress((PPAP_ADDROBJ)pObject);
break;
case ATALK_DEV_ADSP:
pDdpAddr = AtalkAdspGetDdpAddress((PADSP_ADDROBJ)pObject);
break;
default:
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
("AtalkNbpTdiAction: Invalid device type !!\n"));
error = ATALK_INVALID_REQUEST;
break;
}
// reference the Ddp address.
if ((pActReq->ar_ActionCode == COMMON_ACTION_NBPREGISTER_BY_ADDR) ||
(pActReq->ar_ActionCode == COMMON_ACTION_NBPREMOVE_BY_ADDR))
{
// In this case, we don't want to access the object related to
// the filehandle in the IO request, we want to access the object
// related to a specific user socket address.
pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisterTuple);
AtalkDdpReferenceByAddr(AtalkDefaultPort,
&(pNbpTuple->tpl_Address),
&pDdpAddr,
&error);
}
else
{
AtalkDdpReferenceByPtr(pDdpAddr, &error);
}
if (!ATALK_SUCCESS(error))
{
AtalkUnlockNbpIfNecessary();
return error;
}
// Call Nbp to do the right stuff
switch (pActReq->ar_ActionCode)
{
case COMMON_ACTION_NBPLOOKUP:
pNbpTuple = (PNBPTUPLE)(&((PNBP_LOOKUP_PARAMS)(pActReq->ar_pParms))->LookupTuple);
error = AtalkNbpAction(pDdpAddr,
FOR_LOOKUP,
pNbpTuple,
pActReq->ar_pAMdl,
(USHORT)(pActReq->ar_MdlSize/sizeof(NBPTUPLE)),
pActReq);
break;
case COMMON_ACTION_NBPCONFIRM:
pNbpTuple = (PNBPTUPLE)(&((PNBP_CONFIRM_PARAMS)(pActReq->ar_pParms))->ConfirmTuple);
error = AtalkNbpAction(pDdpAddr,
FOR_CONFIRM,
pNbpTuple,
NULL,
0,
pActReq);
break;
case COMMON_ACTION_NBPREGISTER:
pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisterTuple);
error = AtalkNbpAction(pDdpAddr,
FOR_REGISTER,
pNbpTuple,
NULL,
0,
pActReq);
break;
case COMMON_ACTION_NBPREMOVE:
pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisteredTuple);
error = AtalkNbpRemove(pDdpAddr,
pNbpTuple,
pActReq);
break;
case COMMON_ACTION_NBPREGISTER_BY_ADDR:
pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisterTuple);
error = AtalkNbpAction(pDdpAddr,
FOR_REGISTER,
pNbpTuple,
NULL,
0,
pActReq);
break;
case COMMON_ACTION_NBPREMOVE_BY_ADDR:
pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisteredTuple);
error = AtalkNbpRemove(pDdpAddr,
pNbpTuple,
pActReq);
break;
default:
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
("AtalkNbpTdiAction: Invalid Nbp Action !!\n"));
error = ATALK_INVALID_REQUEST;
break;
}
AtalkDdpDereference(pDdpAddr);
if (error != ATALK_PENDING)
{
AtalkUnlockNbpIfNecessary();
}
return error;
}
ATALK_ERROR
AtalkZipTdiAction(
IN PVOID pObject, // Address or Connection object
IN PACTREQ pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for ZIP TdiAction calls. The parameters are validated and
the calls are dispacthed to the appropriate ZIP routines.
Arguments:
Return Value:
--*/
{
ATALK_ERROR error = ATALK_INVALID_PARAMETER;
PPORT_DESCRIPTOR pPortDesc = AtalkDefaultPort;
PWCHAR PortName = NULL;
USHORT PortNameLen;
UNICODE_STRING AdapterName, UpcaseAdapterName;
WCHAR UpcaseBuffer[MAX_INTERNAL_PORTNAME_LEN];
KIRQL OldIrql;
int i;
PAGED_CODE ();
// Lock the Zip stuff, if this is the first zip action
AtalkLockZipIfNecessary();
ASSERT (VALID_ACTREQ(pActReq));
if ((pActReq->ar_ActionCode == COMMON_ACTION_ZIPGETLZONESONADAPTER) ||
(pActReq->ar_ActionCode == COMMON_ACTION_ZIPGETADAPTERDEFAULTS))
{
// Map the port name to the port descriptor
if ((pActReq->ar_pAMdl != NULL) && (pActReq->ar_MdlSize > 0))
{
PortName = (PWCHAR)AtalkGetAddressFromMdlSafe(
pActReq->ar_pAMdl,
NormalPagePriority);
}
if (PortName == NULL)
{
AtalkUnlockZipIfNecessary();
return ATALK_INVALID_PARAMETER;
}
PortNameLen = pActReq->ar_MdlSize/sizeof(WCHAR);
// make sure there is a NULL char in the buffer
for (i=0; i<PortNameLen; i++)
{
if (PortName[i] == UNICODE_NULL)
{
break;
}
}
// didn't find null char within limit? bad parameter..
if (i >= MAX_INTERNAL_PORTNAME_LEN)
{
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
("AtalkZipTdiAction: port name too big (%d) for %lx\n",PortNameLen,PortName));
ASSERT(0);
return ATALK_INVALID_PARAMETER;
}
PortNameLen = (USHORT)i;
AdapterName.Buffer = PortName;
AdapterName.Length = (PortNameLen)*sizeof(WCHAR);
AdapterName.MaximumLength = (PortNameLen+1)*sizeof(WCHAR);
UpcaseAdapterName.Buffer = UpcaseBuffer;
UpcaseAdapterName.Length =
UpcaseAdapterName.MaximumLength = sizeof(UpcaseBuffer);
RtlUpcaseUnicodeString(&UpcaseAdapterName,
&AdapterName,
FALSE);
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
// Find the port corres. to the port descriptor
for (pPortDesc = AtalkPortList;
pPortDesc != NULL;
pPortDesc = pPortDesc->pd_Next)
{
if ((UpcaseAdapterName.Length == pPortDesc->pd_AdapterName.Length) &&
RtlEqualMemory(UpcaseAdapterName.Buffer,
pPortDesc->pd_AdapterName.Buffer,
UpcaseAdapterName.Length))
{
break;
}
}
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
if (pPortDesc == NULL)
{
AtalkUnlockZipIfNecessary();
return ATALK_INVALID_PARAMETER;
}
}
else if (pActReq->ar_ActionCode == COMMON_ACTION_ZIPGETZONELIST)
{
PPORT_DESCRIPTOR pTempPortDesc = NULL;
// This is to take care of cases when zone list is requested
// but the default adapter has gone away during PnP, and
// AtalkDefaultPort points to NULL
if (pPortDesc == NULL)
{
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
("COMMON_ACTION_ZIPGETZONELIST: PortDesc points to NULL\n"));
AtalkUnlockZipIfNecessary();
return ATALK_PORT_INVALID;
}
// Check if the AtalkDefaultPort is still in the list
// It is possible that AtalkDefaultPort holds a non-NULL value, but
// the adapter has gone away during a PnP
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
// Find the port corres. to the port descriptor
for (pTempPortDesc = AtalkPortList;
pTempPortDesc != NULL;
pTempPortDesc = pTempPortDesc->pd_Next)
{
if (pTempPortDesc == pPortDesc)
{
break;
}
}
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
if (pTempPortDesc == NULL)
{
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
("COMMON_ACTION_ZIPGETZONELIST: PortDesc structure has gone away during PnP\n"));
AtalkUnlockZipIfNecessary();
return ATALK_PORT_INVALID;
}
}
switch (pActReq->ar_ActionCode)
{
case COMMON_ACTION_ZIPGETMYZONE:
error = AtalkZipGetMyZone( pPortDesc,
TRUE,
pActReq->ar_pAMdl,
pActReq->ar_MdlSize,
pActReq);
break;
case COMMON_ACTION_ZIPGETZONELIST:
error = AtalkZipGetZoneList(pPortDesc,
FALSE,
pActReq->ar_pAMdl,
pActReq->ar_MdlSize,
pActReq);
break;
case COMMON_ACTION_ZIPGETADAPTERDEFAULTS:
// Copy the network range from the port and fall through
((PZIP_GETPORTDEF_PARAMS)(pActReq->ar_pParms))->NwRangeLowEnd =
pPortDesc->pd_NetworkRange.anr_FirstNetwork;
((PZIP_GETPORTDEF_PARAMS)(pActReq->ar_pParms))->NwRangeHighEnd =
pPortDesc->pd_NetworkRange.anr_LastNetwork;
error = AtalkZipGetMyZone(pPortDesc,
FALSE,
pActReq->ar_pAMdl,
pActReq->ar_MdlSize,
pActReq);
break;
case COMMON_ACTION_ZIPGETLZONESONADAPTER:
case COMMON_ACTION_ZIPGETLZONES:
error = AtalkZipGetZoneList(pPortDesc,
TRUE,
pActReq->ar_pAMdl,
pActReq->ar_MdlSize,
pActReq);
break;
default:
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
("AtalkZipTdiAction: Invalid Zip Action !!\n"));
error = ATALK_INVALID_REQUEST;
break;
}
if (error != ATALK_PENDING)
{
AtalkUnlockZipIfNecessary();
}
return error;
}
ATALK_ERROR
AtalkAspTdiAction(
IN PVOID pObject, // Address or Connection object
IN PACTREQ pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for ASP TdiAction calls. The parameters are validated and
the calls are dispacthed to the appropriate ASP routines.
The only ASP Action is: ASP_XCHG_ENTRIES
Arguments:
Return Value:
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PAGED_CODE ();
ASSERT(VALID_ACTREQ(pActReq));
if (pActReq->ar_ActionCode == ACTION_ASP_BIND)
{
if (AtalkAspReferenceAddr((PASP_ADDROBJ)pObject) != NULL)
{
error = AtalkAspBind((PASP_ADDROBJ)pObject,
(PASP_BIND_PARAMS)(pActReq->ar_pParms),
pActReq);
AtalkAspDereferenceAddr((PASP_ADDROBJ)pObject);
}
}
return error;
}
ATALK_ERROR
AtalkAdspTdiAction(
IN PVOID pObject, // Address or Connection object
IN PACTREQ pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for ADSP TdiAction calls. The parameters are validated and
the calls are dispacthed to the appropriate ADSP routines.
Arguments:
Return Value:
--*/
{
ATALK_ERROR error = ATALK_NO_ERROR;
PAGED_CODE ();
ASSERT (VALID_ACTREQ(pActReq));
return error;
}
ATALK_ERROR
AtalkAspCTdiAction(
IN PVOID pObject, // Address or Connection object
IN PACTREQ pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for ASP Client TdiAction calls. The parameters are validated
and the calls are dispatched to the appropriate ASP routines.
Arguments:
Return Value:
--*/
{
ATALK_ERROR error = ATALK_NO_ERROR;
PAMDL pReplyMdl;
ATALK_ADDR atalkAddr;
BOOLEAN fWrite;
PAGED_CODE ();
ASSERT (VALID_ACTREQ(pActReq));
switch (pActReq->ar_ActionCode)
{
case ACTION_ASPCGETSTATUS:
AtalkAspCAddrReference((PASPC_ADDROBJ)pObject, &error);
if (ATALK_SUCCESS(error))
{
TDI_TO_ATALKADDR(&atalkAddr,
&(((PASPC_GETSTATUS_PARAMS)pActReq->ar_pParms)->ServerAddr));
error = AtalkAspCGetStatus((PASPC_ADDROBJ)pObject,
&atalkAddr,
pActReq->ar_pAMdl,
pActReq->ar_MdlSize,
pActReq);
AtalkAspCAddrDereference((PASPC_ADDROBJ)pObject);
}
break;
case ACTION_ASPCCOMMAND:
case ACTION_ASPCWRITE:
// Split the mdl into command and reply/write mdls. The already constructed mdl
// serves as the command mdl
// First validate that the sizes are valid
if (pActReq->ar_MdlSize < (((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->CmdSize +
((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->WriteAndReplySize))
{
error = ATALK_BUFFER_TOO_SMALL;
break;
}
pReplyMdl = AtalkSubsetAmdl(pActReq->ar_pAMdl,
((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->CmdSize,
((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->WriteAndReplySize);
if (pReplyMdl == NULL)
{
error = ATALK_RESR_MEM;
break;
}
AtalkAspCConnReference((PASPC_CONNOBJ)pObject, &error);
if (ATALK_SUCCESS(error))
{
fWrite = (pActReq->ar_ActionCode == ACTION_ASPCWRITE) ? TRUE : FALSE;
error = AtalkAspCCmdOrWrite((PASPC_CONNOBJ)pObject,
pActReq->ar_pAMdl,
((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->CmdSize,
pReplyMdl,
((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->WriteAndReplySize,
fWrite,
pActReq);
AtalkAspCConnDereference((PASPC_CONNOBJ)pObject);
}
break;
default:
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
("AtalkAspCTdiAction: Invalid Asp Client Action !!\n"));
error = ATALK_INVALID_REQUEST;
break;
}
return error;
}
ATALK_ERROR
AtalkPapTdiAction(
IN PVOID pObject, // Address or Connection object
IN PACTREQ pActReq // Pointer to action request
)
/*++
Routine Description:
This is the entry for PAP TdiAction calls. The parameters are validated and
the calls are dispacthed to the appropriate PAP routines.
Arguments:
Return Value:
--*/
{
ATALK_ERROR error;
ATALK_ADDR atalkAddr;
PAGED_CODE ();
ASSERT (VALID_ACTREQ(pActReq));
switch (pActReq->ar_ActionCode)
{
case ACTION_PAPGETSTATUSSRV:
AtalkPapAddrReference((PPAP_ADDROBJ)pObject, &error);
if (ATALK_SUCCESS(error))
{
TDI_TO_ATALKADDR(
&atalkAddr,
&(((PPAP_GETSTATUSSRV_PARAMS)pActReq->ar_pParms)->ServerAddr));
error = AtalkPapGetStatus((PPAP_ADDROBJ)pObject,
&atalkAddr,
pActReq->ar_pAMdl,
pActReq->ar_MdlSize,
pActReq);
AtalkPapAddrDereference((PPAP_ADDROBJ)pObject);
}
break;
case ACTION_PAPSETSTATUS:
AtalkPapAddrReference((PPAP_ADDROBJ)pObject, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapSetStatus((PPAP_ADDROBJ)pObject,
pActReq->ar_pAMdl,
pActReq);
AtalkPapAddrDereference((PPAP_ADDROBJ)pObject);
}
break;
case ACTION_PAPPRIMEREAD:
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pObject, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapPrimeRead((PPAP_CONNOBJ)pObject, pActReq);
AtalkPapConnDereference((PPAP_CONNOBJ)pObject);
}
break;
default:
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
("AtalkPapTdiAction: Invalid Pap Action !!\n"));
error = ATALK_INVALID_REQUEST;
break;
}
return error;
}