Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3406 lines
83 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
atktdi.c
Abstract:
This module contains the code providing the tdi interface.
Author:
Jameel Hyder ([email protected])
Nikhil Kamkolkar ([email protected])
Revision History:
19 Jun 1992 Initial Version
Notes: Tab stop: 4
--*/
#include <atalk.h>
#pragma hdrstop
#define FILENUM ATKTDI
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, AtalkLockInit)
#pragma alloc_text(PAGE, AtalkTdiOpenAddress)
#pragma alloc_text(PAGE, AtalkTdiOpenConnection)
//#pragma alloc_text(PAGE, AtalkTdiOpenControlChannel)
#pragma alloc_text(PAGE, AtalkTdiAction)
#pragma alloc_text(PAGE, atalkQueuedLockUnlock)
#pragma alloc_text(PAGE_TDI, AtalkTdiCleanupAddress)
#pragma alloc_text(PAGE_TDI, AtalkTdiCleanupConnection)
#pragma alloc_text(PAGE_TDI, AtalkTdiCloseAddress)
#pragma alloc_text(PAGE_TDI, AtalkTdiCloseConnection)
#pragma alloc_text(PAGE_TDI, AtalkTdiCloseControlChannel)
#pragma alloc_text(PAGE_TDI, AtalkTdiAssociateAddress)
#pragma alloc_text(PAGE_TDI, AtalkTdiDisassociateAddress)
#pragma alloc_text(PAGE_TDI, AtalkTdiConnect)
#pragma alloc_text(PAGE_TDI, AtalkTdiDisconnect)
#pragma alloc_text(PAGE_TDI, AtalkTdiAccept)
#pragma alloc_text(PAGE_TDI, AtalkTdiListen)
#pragma alloc_text(PAGE_TDI, AtalkTdiSend)
#pragma alloc_text(PAGE_TDI, AtalkTdiSendDgram)
#pragma alloc_text(PAGE_TDI, AtalkTdiReceive)
#pragma alloc_text(PAGE_TDI, AtalkTdiReceiveDgram)
#pragma alloc_text(PAGE_TDI, AtalkTdiQueryInformation)
#pragma alloc_text(PAGE_TDI, AtalkTdiSetInformation)
#pragma alloc_text(PAGE_TDI, AtalkTdiSetEventHandler)
#pragma alloc_text(PAGE_TDI, AtalkTdiCancel)
#pragma alloc_text(PAGE_TDI, AtalkQueryInitProviderInfo)
#pragma alloc_text(PAGE_TDI, atalkTdiActionComplete)
#pragma alloc_text(PAGE_TDI, atalkTdiGenericComplete)
#pragma alloc_text(PAGE_TDI, atalkTdiGenericReadComplete)
#pragma alloc_text(PAGE_TDI, atalkTdiGenericWriteComplete)
#endif
// Primary TDI Functions for appletalk stack
NTSTATUS
AtalkTdiOpenAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN PTA_APPLETALK_ADDRESS pTdiAddr,
IN BYTE ProtoType,
IN BYTE SocketType,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine is used to create an address object. It will also the
create the appropriate socket with the portable stack.
Arguments:
Return Value:
STATUS_SUCCESS if address was successfully opened
Error otherwise.
--*/
{
PVOID FsContext;
ATALK_ADDR atalkAddr;
ATALK_ERROR error;
do
{
atalkWaitDefaultPort();
// We honor only if count/type and length are as we expect. And only if the
// default port is valid.
if ((AtalkDefaultPort == NULL) ||
(AtalkDefaultPort->pd_Flags & PD_PNP_RECONFIGURE) ||
(pTdiAddr->TAAddressCount != 1) ||
(pTdiAddr->Address[0].AddressLength < sizeof(TDI_ADDRESS_APPLETALK)) ||
(pTdiAddr->Address[0].AddressType != TDI_ADDRESS_TYPE_APPLETALK))
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenAddress: returning STATUS_INVALID_ADDRESS (%lx)\n",AtalkDefaultPort));
error = ATALK_NEW_SOCKET; // maps to STATUS_INVALID_ADDRESS
break;
}
TDI_TO_ATALKADDR(&atalkAddr, pTdiAddr);
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
error = AtalkDdpOpenAddress(AtalkDefaultPort,
atalkAddr.ata_Socket,
NULL, // Desired node (any node)
NULL, // NULL Socket Handler
NULL, // Context for handler
ProtoType,
pCtx,
(PDDP_ADDROBJ *)(&FsContext));
break;
case ATALK_DEV_ASPC:
AtalkLockAspCIfNecessary();
error = AtalkAspCCreateAddress(pCtx, (PASPC_ADDROBJ *)(&FsContext));
break;
case ATALK_DEV_ASP:
AtalkLockAspIfNecessary();
error = AtalkAspCreateAddress((PASP_ADDROBJ *)(&FsContext));
break;
case ATALK_DEV_PAP:
AtalkLockPapIfNecessary();
error = AtalkPapCreateAddress(pCtx, (PPAP_ADDROBJ *)(&FsContext));
break;
case ATALK_DEV_ADSP:
AtalkLockAdspIfNecessary();
error = AtalkAdspCreateAddress(pCtx,
SocketType,
(PADSP_ADDROBJ *)(&FsContext));
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
error = ATALK_INVALID_REQUEST;
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenAddress: Invalid device type\n"));
break;
}
if (ATALK_SUCCESS(error))
{
pIrpSp->FileObject->FsContext2 =
(PVOID)((ULONG_PTR)(TDI_TRANSPORT_ADDRESS_FILE + (pCtx->adc_DevType << 16)));
pIrpSp->FileObject->FsContext = FsContext;
AtalkLockTdiIfNecessary();
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiOpenConnection(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN CONNECTION_CONTEXT ConnCtx,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine is used to create a connection object and associate the
passed ConnectionContext with it.
Arguments:
ConnectionContext - The TDI ConnectionContext to be associated with object
Context - The DeviceContext of the device on which open is happening
Return Value:
STATUS_SUCCESS if connection was successfully opened
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID FsContext;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP)||
(pCtx->adc_DevType == ATALK_DEV_ASPC))
do
{
atalkWaitDefaultPort();
// Only if the default port is valid.
if (AtalkDefaultPort == NULL)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenConnection: returning STATUS_INVALID_ADDRESS\n"));
error = ATALK_NEW_SOCKET; // maps to STATUS_INVALID_ADDRESS
break;
}
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
AtalkLockPapIfNecessary();
error = AtalkPapCreateConnection(ConnCtx,
pCtx,
(PPAP_CONNOBJ *)(&FsContext));
break;
case ATALK_DEV_ADSP:
AtalkLockAdspIfNecessary();
error = AtalkAdspCreateConnection(ConnCtx,
pCtx,
(PADSP_CONNOBJ *)(&FsContext));
break;
case ATALK_DEV_ASPC:
AtalkLockAspCIfNecessary();
error = AtalkAspCCreateConnection(ConnCtx,
pCtx,
(PASPC_CONNOBJ *)(&FsContext));
break;
}
if (ATALK_SUCCESS(error))
{
pIrpSp->FileObject->FsContext2 = (PVOID)((ULONG_PTR)(TDI_CONNECTION_FILE +
(pCtx->adc_DevType << 16)));
pIrpSp->FileObject->FsContext = FsContext;
AtalkLockTdiIfNecessary();
}
ASSERT(error == ATALK_NO_ERROR);
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiOpenControlChannel(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine is used to create a control channel
Arguments:
Context - The DeviceContext of the device on which open is happening
Return Value:
STATUS_SUCCESS if controlchannel was successfully opened
Error otherwise.
--*/
{
PDDP_ADDROBJ pDdpAddr;
ATALK_ERROR error = ATALK_INVALID_REQUEST;
KIRQL OldIrql;
do
{
if (pCtx->adc_DevType != ATALK_DEV_ARAP)
{
atalkWaitDefaultPort();
// Only if the default port is valid.
if (AtalkDefaultPort == NULL)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenControlChannel: NOT ATALK_DEV_ARAP: returning STATUS_INVALID_ADDRESS\n"));
if (!AtalkNoDefPortPrinted)
{
LOG_ERROR(EVENT_ATALK_NO_DEFAULTPORT, 0, NULL, 0);
AtalkNoDefPortPrinted = TRUE;
}
error = ATALK_NEW_SOCKET; // maps to STATUS_INVALID_ADDRESS
break;
}
}
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
case ATALK_DEV_ASP:
case ATALK_DEV_PAP:
case ATALK_DEV_ADSP:
case ATALK_DEV_ASPC:
error = AtalkDdpOpenAddress(AtalkDefaultPort,
UNKNOWN_SOCKET,
NULL,
NULL,
NULL,
0,
pCtx,
&pDdpAddr);
break;
case ATALK_DEV_ARAP:
if (AtalkDefaultPort == NULL)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenControlChannel: device is ATALK_DEV_ARAP: returning STATUS_INVALID_ADDRESS\n"));
if (!AtalkNoDefPortPrinted)
{
LOG_ERROR(EVENT_ATALK_NO_DEFAULTPORT, 0, NULL, 0);
AtalkNoDefPortPrinted = TRUE;
}
error = ATALK_NEW_SOCKET; // maps to STATUS_INVALID_ADDRESS
break;
}
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,("RAS device opened\n"));
#if DBG
KeQuerySystemTime(&ArapDbgLastTraceTime);
#endif
error = ATALK_NO_ERROR;
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenControlChannel: Invalid device type\n"));
break;
}
if (ATALK_SUCCESS(error))
{
pIrpSp->FileObject->FsContext2 =
(PVOID)((ULONG_PTR)(TDI_CONTROL_CHANNEL_FILE + (pCtx->adc_DevType << 16)));
pIrpSp->FileObject->FsContext = pDdpAddr;
AtalkLockTdiIfNecessary();
}
else
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiOpenControlChannel: Failed %ld\n", error));
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiCleanupAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closepIrp for completion.
Arguments:
pIrp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
ATALK_ERROR error;
PVOID pAddrObj = pIrpSp->FileObject->FsContext;
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
if (!(VALID_DDP_ADDROBJ(((PDDP_ADDROBJ)pAddrObj))))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkDdpReferenceByPtr(((PDDP_ADDROBJ)pAddrObj), &error);
if (ATALK_SUCCESS(error))
{
AtalkDdpCleanupAddress((PDDP_ADDROBJ)pAddrObj);
AtalkDdpDereference(((PDDP_ADDROBJ)pAddrObj));
}
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCAO((PASPC_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkLockAspCIfNecessary();
AtalkAspCAddrReference((PASPC_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
AtalkAspCCleanupAddress((PASPC_ADDROBJ)pAddrObj);
AtalkAspCAddrDereference((PASPC_ADDROBJ)pAddrObj);
}
AtalkUnlockAspCIfNecessary();
break;
case ATALK_DEV_ASP:
error = ATALK_NO_ERROR;
break;
case ATALK_DEV_PAP:
if (!(VALID_PAPAO((PPAP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkLockPapIfNecessary();
AtalkPapAddrReference((PPAP_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
AtalkPapCleanupAddress((PPAP_ADDROBJ)pAddrObj);
AtalkPapAddrDereference((PPAP_ADDROBJ)pAddrObj);
}
AtalkUnlockPapIfNecessary();
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPAO((PADSP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkLockAdspIfNecessary();
AtalkAdspAddrReference((PADSP_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
AtalkAdspCleanupAddress((PADSP_ADDROBJ)pAddrObj);
AtalkAdspAddrDereference((PADSP_ADDROBJ)pAddrObj);
}
AtalkUnlockAdspIfNecessary();
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiCleanupAddress: Invalid device type\n"));
error = ATALK_INVALID_REQUEST;
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiCleanupConnection(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closepIrp for completion.
Arguments:
pIrp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
ATALK_ERROR error;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockPapIfNecessary();
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
// No need to have lock as we have a reference.
((PPAP_CONNOBJ)pConnObj)->papco_CleanupComp = atalkTdiGenericComplete;
((PPAP_CONNOBJ)pConnObj)->papco_CleanupCtx = pIrp;
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("AtalkTdiCleanupConnection: Cleanup %lx.%lx\n",
pConnObj, pIrp));
AtalkPapCleanupConnection((PPAP_CONNOBJ)pConnObj);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
error = ATALK_PENDING;
}
AtalkUnlockPapIfNecessary();
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAdspIfNecessary();
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
// No need to have lock as we have a reference.
((PADSP_CONNOBJ)pConnObj)->adspco_CleanupComp = atalkTdiGenericComplete;
((PADSP_CONNOBJ)pConnObj)->adspco_CleanupCtx = pIrp;
AtalkAdspCleanupConnection((PADSP_CONNOBJ)pConnObj);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
error = ATALK_PENDING;
}
AtalkUnlockAdspIfNecessary();
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAspCIfNecessary();
AtalkAspCConnReference((PASPC_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
// No need to have lock as we have a reference.
((PASPC_CONNOBJ)pConnObj)->aspcco_CleanupComp = atalkTdiGenericComplete;
((PASPC_CONNOBJ)pConnObj)->aspcco_CleanupCtx = pIrp;
AtalkAspCCleanupConnection((PASPC_CONNOBJ)pConnObj);
AtalkAspCConnDereference((PASPC_CONNOBJ)pConnObj);
error = ATALK_PENDING;
}
AtalkUnlockAspCIfNecessary();
break;
case ATALK_DEV_DDP:
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiCleanupConnection: Invalid device type\n"));
error = ATALK_INVALID_REQUEST;
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiCloseAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closepIrp for completion.
Arguments:
pIrp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
ATALK_ERROR error;
PVOID pAddrObj = pIrpSp->FileObject->FsContext;
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
if (!(VALID_DDP_ADDROBJ(((PDDP_ADDROBJ)pAddrObj))))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkDdpReferenceByPtr(((PDDP_ADDROBJ)pAddrObj), &error);
if (ATALK_SUCCESS(error))
{
error = AtalkDdpCloseAddress((PDDP_ADDROBJ)pAddrObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkDdpDereference(((PDDP_ADDROBJ)pAddrObj));
}
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCAO((PASPC_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkAspCAddrReference((PASPC_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAspCCloseAddress((PASPC_ADDROBJ)pAddrObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkAspCAddrDereference((PASPC_ADDROBJ)pAddrObj);
}
break;
case ATALK_DEV_ASP:
if (!(VALID_ASPAO((PASP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
if (AtalkAspReferenceAddr((PASP_ADDROBJ)pAddrObj) != NULL)
{
error = AtalkAspCloseAddress((PASP_ADDROBJ)pAddrObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkAspDereferenceAddr((PASP_ADDROBJ)pAddrObj);
}
break;
case ATALK_DEV_PAP:
if (!(VALID_PAPAO((PPAP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkPapAddrReference((PPAP_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapCloseAddress((PPAP_ADDROBJ)pAddrObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkPapAddrDereference((PPAP_ADDROBJ)pAddrObj);
}
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPAO((PADSP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkAdspAddrReference((PADSP_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspCloseAddress((PADSP_ADDROBJ)pAddrObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkAdspAddrDereference((PADSP_ADDROBJ)pAddrObj);
}
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
error = ATALK_INVALID_REQUEST;
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiCloseAddress: Invalid device type\n"));
break;
}
} while (FALSE);
if (error == ATALK_NO_ERROR)
error = ATALK_PENDING;
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiCloseConnection(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closepIrp for completion.
Arguments:
pIrp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP)||
(pCtx->adc_DevType == ATALK_DEV_ASPC))
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockPapIfNecessary();
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapCloseConnection((PPAP_CONNOBJ)pConnObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
}
AtalkUnlockPapIfNecessary();
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAdspIfNecessary();
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspCloseConnection((PADSP_CONNOBJ)pConnObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
}
AtalkUnlockAdspIfNecessary();
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAspCIfNecessary();
if (!AtalkAspCConnectionIsValid((PASPC_CONNOBJ)pConnObj))
{
error = ATALK_INVALID_CONNECTION;
AtalkUnlockAspCIfNecessary();
break;
}
AtalkAspCConnReference((PASPC_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAspCCloseConnection((PASPC_CONNOBJ)pConnObj,
atalkTdiCloseAddressComplete,
pIrp);
AtalkAspCConnDereference((PASPC_CONNOBJ)pConnObj);
}
AtalkUnlockAspCIfNecessary();
break;
}
} while (FALSE);
if (error == ATALK_NO_ERROR)
error = ATALK_PENDING;
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiCloseControlChannel(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closepIrp for completion.
Arguments:
pIrp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
ATALK_ERROR error;
PVOID pCtrlChnl = pIrpSp->FileObject->FsContext;
KIRQL OldIrql;
if (pCtx->adc_DevType == ATALK_DEV_ARAP)
{
ArapReleaseResources();
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
("AtalkTdiCloseAddress: RAS device closed\n"));
// flip the state, so if engine restarts, we tell the engine
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
if (ArapStackState == ARAP_STATE_ACTIVE)
{
ArapStackState = ARAP_STATE_ACTIVE_WAITING;
}
else if (ArapStackState == ARAP_STATE_INACTIVE)
{
ArapStackState = ARAP_STATE_INACTIVE_WAITING;
}
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
AtalkUnlockTdiIfNecessary();
return(STATUS_SUCCESS);
}
if (!(VALID_DDP_ADDROBJ((PDDP_ADDROBJ)pCtrlChnl)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
return AtalkErrorToNtStatus(error);
}
AtalkDdpReferenceByPtr(((PDDP_ADDROBJ)pCtrlChnl), &error);
if (ATALK_SUCCESS(error))
{
error = AtalkDdpCloseAddress(((PDDP_ADDROBJ)pCtrlChnl),
atalkTdiCloseAddressComplete,
pIrp);
AtalkDdpDereference(((PDDP_ADDROBJ)pCtrlChnl));
}
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiAssociateAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine will associate the connection object with the specified
address object.
This routine is pretty much provider independent. All we check for is
that the address object and the provider object belong to the same device.
Also, this routine will complete synchronously.
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pAddrObj;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
PFILE_OBJECT pFileObj = NULL;
HANDLE AddrObjHandle =
((PTDI_REQUEST_KERNEL_ASSOCIATE)(&pIrpSp->Parameters))->AddressHandle;
PDEVICE_OBJECT pDeviceObject;
NTSTATUS status;
DWORD i;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP)||
(pCtx->adc_DevType == ATALK_DEV_ASPC))
do
{
// Get the handle to the address object from the irp and map it to
// the corres. file object.
{
status = ObReferenceObjectByHandle(AddrObjHandle,
0,
*IoFileObjectType,
pIrp->RequestorMode,
(PVOID *)&pFileObj,
NULL);
ASSERT (NT_SUCCESS(status));
if (!NT_SUCCESS(status))
{
return(status);
}
}
pDeviceObject = IoGetRelatedDeviceObject(pFileObj);
status = STATUS_OBJECT_NAME_INVALID;
for (i=0; i < ATALK_NO_DEVICES; i++ )
{
if (pDeviceObject == (PDEVICE_OBJECT)AtalkDeviceObject[i])
{
status = STATUS_SUCCESS;
break;
}
}
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiAssociateAddress: wrong devObject %lx\n",pDeviceObject));
ASSERT(0);
return(status);
}
pAddrObj = pFileObj->FsContext;
ASSERT(((LONG_PTR)pFileObj->FsContext2 >> 16) == pCtx->adc_DevType);
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPAO((PPAP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkLockPapIfNecessary();
AtalkPapAddrReference((PPAP_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
AtalkPapAddrDereference((PPAP_ADDROBJ)pAddrObj);
break;
}
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapAssociateAddress((PPAP_ADDROBJ)pAddrObj,
(PPAP_CONNOBJ)pConnObj);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
}
AtalkPapAddrDereference((PPAP_ADDROBJ)pAddrObj);
}
AtalkUnlockPapIfNecessary();
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPAO((PADSP_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkLockAdspIfNecessary();
AtalkAdspAddrReference((PADSP_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
AtalkAdspAddrDereference((PADSP_ADDROBJ)pAddrObj);
break;
}
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspAssociateAddress((PADSP_ADDROBJ)pAddrObj,
(PADSP_CONNOBJ)pConnObj);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
}
AtalkAdspAddrDereference((PADSP_ADDROBJ)pAddrObj);
}
AtalkUnlockAdspIfNecessary();
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCAO((PASPC_ADDROBJ)pAddrObj)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
AtalkLockAspCIfNecessary();
AtalkAspCAddrReference((PASPC_ADDROBJ)pAddrObj, &error);
if (ATALK_SUCCESS(error))
{
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
AtalkAspCAddrDereference((PASPC_ADDROBJ)pAddrObj);
break;
}
AtalkAspCConnReference((PASPC_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAspCAssociateAddress((PASPC_ADDROBJ)pAddrObj,
(PASPC_CONNOBJ)pConnObj);
AtalkAspCConnDereference((PASPC_CONNOBJ)pConnObj);
}
AtalkAspCAddrDereference((PASPC_ADDROBJ)pAddrObj);
}
AtalkUnlockAspCIfNecessary();
break;
}
// Dereference the file object corres. to the address object
ObDereferenceObject(pFileObj);
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiDisassociateAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine performs a disassociate. This request is only valid when
the connection is in a purely ASSOCIATED state.
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP)||
(pCtx->adc_DevType == ATALK_DEV_ASPC))
do
{
ASSERT(((LONG_PTR)pIrpSp->FileObject->FsContext2 >> 16) == pCtx->adc_DevType);
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
// Reference the connection object
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockPapIfNecessary();
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapDissociateAddress(pConnObj);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
}
AtalkUnlockPapIfNecessary();
break;
case ATALK_DEV_ADSP:
// Reference the connection object
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAdspIfNecessary();
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspDissociateAddress(pConnObj);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
}
AtalkUnlockAdspIfNecessary();
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAspCIfNecessary();
if (!AtalkAspCConnectionIsValid((PASPC_CONNOBJ)pConnObj))
{
error = ATALK_INVALID_CONNECTION;
AtalkUnlockAspCIfNecessary();
break;
}
// Reference the connection object
AtalkAspCConnReference((PASPC_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAspCDissociateAddress(pConnObj);
AtalkAspCConnDereference((PASPC_CONNOBJ)pConnObj);
}
AtalkUnlockAspCIfNecessary();
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiConnect(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine will post a connect request with the portable stack.
Arguments:
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
PTDI_REQUEST_KERNEL_CONNECT parameters;
PTA_APPLETALK_ADDRESS remoteTdiAddr;
ATALK_ADDR remoteAddr;
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
parameters = (PTDI_REQUEST_KERNEL_CONNECT)&pIrpSp->Parameters;
remoteTdiAddr = (PTA_APPLETALK_ADDRESS)
parameters->RequestConnectionInformation->RemoteAddress;
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("AtalkTdiConnect: Net %x Node %x Socket %x\n",
remoteTdiAddr->Address[0].Address[0].Network,
remoteTdiAddr->Address[0].Address[0].Node,
remoteTdiAddr->Address[0].Address[0].Socket));
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("AtalkConnPostConnect: Cnt %x\n", remoteTdiAddr->TAAddressCount));
TDI_TO_ATALKADDR(&remoteAddr, remoteTdiAddr);
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("AtalkTdiConnect: Portable Net %x Node %x Socket %x\n",
remoteAddr.ata_Network, remoteAddr.ata_Node, remoteAddr.ata_Socket));
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP)||
(pCtx->adc_DevType == ATALK_DEV_ASPC))
do
{
ASSERT(((LONG_PTR)pIrpSp->FileObject->FsContext2 >> 16) == pCtx->adc_DevType);
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapPostConnect((PPAP_CONNOBJ)pConnObj,
&remoteAddr,
pIrp,
atalkTdiGenericComplete);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
}
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspPostConnect((PADSP_CONNOBJ)pConnObj,
&remoteAddr,
pIrp,
atalkTdiGenericComplete);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
}
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
if (!AtalkAspCConnectionIsValid((PASPC_CONNOBJ)pConnObj))
{
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkAspCConnReference((PASPC_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAspCPostConnect((PASPC_CONNOBJ)pConnObj,
&remoteAddr,
pIrp,
atalkTdiGenericComplete);
AtalkAspCConnDereference((PASPC_CONNOBJ)pConnObj);
}
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiDisconnect(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine will disconnect an active connection or cancel a posted
listen/connect
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP)||
(pCtx->adc_DevType == ATALK_DEV_ASPC))
do
{
ASSERT(((LONG_PTR)pIrpSp->FileObject->FsContext2 >> 16) == pCtx->adc_DevType);
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapDisconnect((PPAP_CONNOBJ)pConnObj,
ATALK_LOCAL_DISCONNECT,
pIrp,
atalkTdiGenericComplete);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
}
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspDisconnect((PADSP_CONNOBJ)pConnObj,
ATALK_LOCAL_DISCONNECT,
pIrp,
atalkTdiGenericComplete);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
}
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
if (!AtalkAspCConnectionIsValid((PASPC_CONNOBJ)pConnObj))
{
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkAspCConnReference((PASPC_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAspCDisconnect((PASPC_CONNOBJ)pConnObj,
ATALK_LOCAL_DISCONNECT,
pIrp,
atalkTdiGenericComplete);
AtalkAspCConnDereference((PASPC_CONNOBJ)pConnObj);
}
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiAccept(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
do
{
ASSERT(((LONG_PTR)pIrpSp->FileObject->FsContext2 >> 16) == pCtx->adc_DevType);
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_ADSP:
case ATALK_DEV_PAP:
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiAccept: Invalid device type\n"));
case ATALK_DEV_DDP:
case ATALK_DEV_ASPC:
case ATALK_DEV_ASP:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
} while (FALSE);
return status;
}
NTSTATUS
AtalkTdiListen(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine
Arguments:
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj = pIrpSp->FileObject->FsContext;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP))
do
{
ASSERT(((LONG_PTR)pIrpSp->FileObject->FsContext2 >> 16) == pCtx->adc_DevType);
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkPapPostListen((PPAP_CONNOBJ)pConnObj,
pIrp,
atalkTdiGenericComplete);
AtalkPapConnDereference((PPAP_CONNOBJ)pConnObj);
}
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkAdspConnReferenceByPtr((PADSP_CONNOBJ)pConnObj, &error);
if (ATALK_SUCCESS(error))
{
error = AtalkAdspPostListen((PADSP_CONNOBJ)pConnObj,
pIrp,
atalkTdiGenericComplete);
AtalkAdspConnDereference((PADSP_CONNOBJ)pConnObj);
}
break;
}
} while (FALSE);
if (error == ATALK_NO_ERROR)
error = ATALK_PENDING;
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiSendDgram(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine sends a datagram.
Arguments:
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
SEND_COMPL_INFO SendInfo;
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
{
PTDI_REQUEST_KERNEL_SENDDG pParam;
PBUFFER_DESC pBufDesc;
ATALK_ERROR error;
PTA_APPLETALK_ADDRESS pTaDest;
ATALK_ADDR AtalkAddr;
PDDP_ADDROBJ pDdpAddr;
pDdpAddr = (PDDP_ADDROBJ)pIrpSp->FileObject->FsContext;
if (!(VALID_DDP_ADDROBJ(pDdpAddr)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
break;
}
pParam = (PTDI_REQUEST_KERNEL_SENDDG)&pIrpSp->Parameters;
pTaDest = (PTA_APPLETALK_ADDRESS)
pParam->SendDatagramInformation->RemoteAddress;
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_INFO,
("DDP: SendDatagram - Net %x Node %x Socket %x\n",
pTaDest->Address[0].Address[0].Network,
pTaDest->Address[0].Address[0].Node,
pTaDest->Address[0].Address[0].Socket));
if ((pTaDest->Address[0].AddressType != TDI_ADDRESS_TYPE_APPLETALK) ||
(pTaDest->Address[0].AddressLength < sizeof(TDI_ADDRESS_APPLETALK)))
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiSendDgram: returning STATUS_INVALID_ADDRESS (Type %x Len %d)\n",
pTaDest->Address[0].AddressType,pTaDest->Address[0].AddressLength));
status = STATUS_INVALID_ADDRESS;
}
else
{
ULONG sendLength;
AtalkAddr.ata_Network = pTaDest->Address[0].Address[0].Network;
AtalkAddr.ata_Node = pTaDest->Address[0].Address[0].Node;
AtalkAddr.ata_Socket = pTaDest->Address[0].Address[0].Socket;
// Get the length of the send mdl
sendLength = AtalkSizeMdlChain(pIrp->MdlAddress);
// Check destination address
if (INVALID_ADDRESS(&AtalkAddr))
{
error = ATALK_DDP_INVALID_ADDR;
}
if (sendLength > MAX_DGRAM_SIZE)
{
error = ATALK_BUFFER_TOO_BIG;
}
else if ((pBufDesc = AtalkAllocBuffDesc(pIrp->MdlAddress,
(USHORT)sendLength,
0)) != NULL)
{
SendInfo.sc_TransmitCompletion = atalkTdiSendDgramComplete;
SendInfo.sc_Ctx1 = pDdpAddr;
SendInfo.sc_Ctx2 = pBufDesc;
SendInfo.sc_Ctx3 = pIrp;
error = AtalkDdpSend(pDdpAddr,
&AtalkAddr,
pDdpAddr->ddpao_Protocol,
FALSE,
pBufDesc,
NULL, // OptHdr
0, // OptHdrLen
NULL, // ZoneMcastAddr
&SendInfo);
if (!ATALK_SUCCESS(error))
{
atalkTdiSendDgramComplete(NDIS_STATUS_FAILURE,
&SendInfo);
error = ATALK_PENDING;
}
}
else error = ATALK_RESR_MEM;
status = AtalkErrorToNtStatus(error);
}
}
break;
case ATALK_DEV_ASPC:
case ATALK_DEV_ADSP:
case ATALK_DEV_ASP:
case ATALK_DEV_PAP:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiSendDatagram: Invalid device type\n"));
break;
}
} while (FALSE);
return status;
}
NTSTATUS
AtalkTdiReceiveDgram(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine receives a datagram.
Arguments:
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
if (pCtx->adc_DevType == ATALK_DEV_DDP)
{
PDDP_ADDROBJ pDdpAddr;
PTDI_REQUEST_KERNEL_RECEIVEDG parameters =
(PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters;
pDdpAddr = (PDDP_ADDROBJ)pIrpSp->FileObject->FsContext;
if (!(VALID_DDP_ADDROBJ(pDdpAddr)))
{
ASSERT(0);
error = ATALK_INVALID_ADDRESS;
return(AtalkErrorToNtStatus(error));
}
error = AtalkDdpReceive(pDdpAddr,
pIrp->MdlAddress,
(USHORT)AtalkSizeMdlChain(pIrp->MdlAddress),
parameters->ReceiveFlags,
atalkTdiRecvDgramComplete,
pIrp);
}
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiSend(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine sends the data specified. (used by PAP/ADSP only)
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
PTDI_REQUEST_KERNEL_SEND parameters;
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj= pIrpSp->FileObject->FsContext;
parameters = (PTDI_REQUEST_KERNEL_SEND)&pIrpSp->Parameters;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ADSP))
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
error = AtalkAdspWrite(pConnObj,
pIrp->MdlAddress,
(USHORT)parameters->SendLength,
parameters->SendFlags,
pIrp,
atalkTdiGenericWriteComplete);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
("AtalkAdspWrite: Failed for conn %lx.%lx error %lx\n",
pConnObj, ((PADSP_CONNOBJ)pConnObj)->adspco_Flags, error));
}
break;
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
error = AtalkPapWrite(pConnObj,
pIrp->MdlAddress,
(USHORT)parameters->SendLength,
parameters->SendFlags,
pIrp,
atalkTdiGenericWriteComplete);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
("AtalkPapWrite: Failed for conn %lx.%lx error %lx\n",
pConnObj, ((PPAP_CONNOBJ)pConnObj)->papco_Flags, error));
}
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiReceive(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine receives data. (used by PAP/ADSP only)
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
ATALK_ERROR error = ATALK_INVALID_REQUEST;
PVOID pConnObj= pIrpSp->FileObject->FsContext;
PTDI_REQUEST_KERNEL_RECEIVE parameters =
(PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
if ((pCtx->adc_DevType == ATALK_DEV_PAP) ||
(pCtx->adc_DevType == ATALK_DEV_ASPC)||
(pCtx->adc_DevType == ATALK_DEV_ADSP))
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_PAP:
if (!(VALID_PAPCO((PPAP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
error = AtalkPapRead(pConnObj,
pIrp->MdlAddress,
(USHORT)parameters->ReceiveLength,
parameters->ReceiveFlags,
pIrp,
atalkTdiGenericReadComplete);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_PAP, DBG_LEVEL_INFO,
("AtalkPapRead: Failed for conn %lx.%lx error %lx\n",
pConnObj, ((PPAP_CONNOBJ)pConnObj)->papco_Flags, error));
}
break;
case ATALK_DEV_ADSP:
if (!(VALID_ADSPCO((PADSP_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
AtalkLockAdspIfNecessary();
error = AtalkAdspRead(pConnObj,
pIrp->MdlAddress,
(USHORT)parameters->ReceiveLength,
parameters->ReceiveFlags,
pIrp,
atalkTdiGenericReadComplete);
AtalkUnlockAdspIfNecessary();
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_ADSP, DBG_LEVEL_INFO,
("AtalkAdspRead: Failed for conn %lx.%lx error %lx\n",
pConnObj, ((PADSP_CONNOBJ)pConnObj)->adspco_Flags, error));
}
break;
case ATALK_DEV_ASPC:
if (!(VALID_ASPCCO((PASPC_CONNOBJ)pConnObj)))
{
ASSERT(0);
error = ATALK_INVALID_CONNECTION;
break;
}
error = AtalkAspCGetAttn(pConnObj,
pIrp->MdlAddress,
(USHORT)parameters->ReceiveLength,
parameters->ReceiveFlags,
pIrp,
atalkTdiGenericReadComplete);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_ASP, DBG_LEVEL_INFO,
("AtalkAspCGetAttn: Failed for conn %lx.%lx error %lx\n",
pConnObj, ((PASPC_CONNOBJ)pConnObj)->aspcco_Flags, error));
}
break;
}
} while (FALSE);
return AtalkErrorToNtStatus(error);
}
NTSTATUS
AtalkTdiAction(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine is the dispatch routine for all the TdiAction primitives
for all the providers
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
ATALK_ERROR error = ATALK_NO_ERROR;
USHORT bufLen;
USHORT actionCode, Flags;
TDI_ACTION_HEADER UNALIGNED *pActionHdr;
PMDL pMdl = pIrp->MdlAddress;
PVOID pObject;
USHORT ObjectType;
USHORT DevType;
BOOLEAN freeHdr = FALSE;
do
{
if (pMdl == NULL)
{
status = STATUS_INVALID_PARAMETER;
break;
}
bufLen = (USHORT)AtalkSizeMdlChain(pIrp->MdlAddress);
// If we atleast do not have the action header, return
if (bufLen < sizeof(TDI_ACTION_HEADER))
{
status = STATUS_INVALID_PARAMETER;
ASSERT(0);
break;
}
if (AtalkIsMdlFragmented(pMdl))
{
ULONG bytesCopied;
if ((pActionHdr = AtalkAllocMemory(sizeof(TDI_ACTION_HEADER))) == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
freeHdr = TRUE;
// Copy the header to this buffer
status = TdiCopyMdlToBuffer(pMdl,
0, // SrcOff
pActionHdr,
0, // Dest Off
sizeof(TDI_ACTION_HEADER),
&bytesCopied);
ASSERT(NT_SUCCESS(status) && (bytesCopied == sizeof(TDI_ACTION_HEADER)));
if (!NT_SUCCESS(status))
break;
}
else
{
pActionHdr = (TDI_ACTION_HEADER UNALIGNED *)MmGetSystemAddressForMdlSafe(
pMdl, NormalPagePriority);
if (pActionHdr == NULL) {
ASSERT(0);
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_INFO,
("AtalkTdiAction - code %lx BufLen %d SysAddress %lx\n",
pActionHdr->ActionCode, bufLen, pActionHdr));
// If the MATK identifier is not present, we return
if (pActionHdr->TransportId != MATK)
{
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
actionCode = pActionHdr->ActionCode;
if ((actionCode < MIN_COMMON_ACTIONCODE) ||
(actionCode > MAX_ALLACTIONCODES))
{
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
("AtalkTdiAction - Invalid action code %d\n", actionCode));
status = STATUS_INVALID_PARAMETER;
break;
}
if (bufLen < AtalkActionDispatch[actionCode]._MinBufLen)
{
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
("AtalkTdiAction - Minbuflen %d Expected %d\n",
bufLen, AtalkActionDispatch[actionCode]._MinBufLen));
status = STATUS_BUFFER_TOO_SMALL;
break;
}
// if someone is trying to open ASP via usermode, reject it!
if ((AtalkActionDispatch[actionCode]._OpCode == ACTION_ASP_BIND) &&
(pIrp->RequestorMode != KernelMode))
{
status = STATUS_INVALID_PARAMETER;
ASSERT(0);
break;
}
Flags = AtalkActionDispatch[actionCode]._Flags;
pObject = (PVOID)pIrpSp->FileObject->FsContext;
ObjectType = (USHORT)((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF);
DevType = (USHORT)((ULONG_PTR)(pIrpSp->FileObject->FsContext2) >> 16);
// Convert control channel operations to Ddp
if (ObjectType == TDI_CONTROL_CHANNEL_FILE)
DevType = ATALK_DEV_DDP;
// Verify the device type is that expected. Either the request
// should be valid for any device or the type of device for the
// request should match the type of device expected.
if ((AtalkActionDispatch[actionCode]._DeviceType != ATALK_DEV_ANY) &&
((pCtx->adc_DevType != AtalkActionDispatch[actionCode]._DeviceType) ||
(DevType != AtalkActionDispatch[actionCode]._DeviceType)))
{
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
// Verify the object - it has to be one of those specified as valid
// in the dispatch table for this action call.
ASSERT(ObjectType & (DFLAG_ADDR | DFLAG_CNTR | DFLAG_CONN));
switch (ObjectType)
{
case TDI_TRANSPORT_ADDRESS_FILE:
if (!(Flags & DFLAG_ADDR))
status = STATUS_INVALID_HANDLE;
break;
case TDI_CONNECTION_FILE:
if (!(Flags & DFLAG_CONN))
status = STATUS_INVALID_HANDLE;
break;
case TDI_CONTROL_CHANNEL_FILE:
if (!(Flags & DFLAG_CNTR))
status = STATUS_INVALID_HANDLE;
break;
default:
status = STATUS_INVALID_HANDLE;
break;
}
} while (FALSE);
if (!NT_SUCCESS(status))
{
if (freeHdr)
{
AtalkFreeMemory(pActionHdr);
}
return status;
}
// Handle the requests based on the action code.
// Use the table to call the appropriate routine
do
{
PACTREQ pActReq;
USHORT offset = AtalkActionDispatch[actionCode]._ActionBufSize;
USHORT size = bufLen - offset;
// If DFLAG_MDL is set, then we know we have to create the mdl.
//
// NOTE: User can pass in invalid sizes...
// Also, it is assumed that BuildMdl will not change
// value of the mdl unless it can successfully build
// all of it. Therefore, error cases must preserve
// value of NULL.
//
// First allocate an action request structure.
// !!!This memory should be zeroed out as we depend on extra mdl pointer to
// be NULL!!!
if ((pActReq = AtalkAllocZeroedMemory(sizeof(ACTREQ))) == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
#if DBG
pActReq->ar_Signature = ACTREQ_SIGNATURE;
#endif
pActReq->ar_pIrp = pIrp;
pActReq->ar_DevType = DevType;
pActReq->ar_pParms = (PBYTE)pActionHdr + sizeof(TDI_ACTION_HEADER);
pActReq->ar_Completion = atalkTdiActionComplete;
pActReq->ar_ActionCode = actionCode;
pActReq->ar_pAMdl = NULL;
pActReq->ar_MdlSize = 0;
if (Flags & DFLAG_MDL)
{
ASSERT((size >= 0) && ((offset+size) <= bufLen));
pActReq->ar_MdlSize = size;
if ((size < 0) || ((offset+size) > bufLen))
{
AtalkFreeMemory(pActReq);
status = STATUS_INVALID_PARAMETER;
break;
}
// If size is zero, we go on to the next mdl.
// IoAllocateMdl will fail for a 0-length mdl
// If size < 0, we will hit the error later.
if (size != 0)
{
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_INFO,
("AtalkTdiAction - Size of mdl %lx\n", size));
pActReq->ar_pAMdl = AtalkSubsetAmdl(pMdl, // MasterMdl
offset, // ByteOffset,
size); // SubsetMdlSize,
if (pActReq->ar_pAMdl == NULL)
{
AtalkFreeMemory(pActReq);
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
}
// Now call the dispatch routine
error = (*AtalkActionDispatch[actionCode]._Dispatch)(pObject, pActReq);
if (!ATALK_SUCCESS(error))
{
// Call the generic completion routine and then return
// pending. That will free up the mdl's and the actreq.
atalkTdiActionComplete(error, pActReq);
}
status = STATUS_PENDING;
} while (FALSE);
return status;
}
NTSTATUS
AtalkTdiQueryInformation(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine will satisfy the query for the object indicated in the Request. It
supports the following query types-
TDI_QUERY_PROVIDER_INFO
The provider information structure for the provider that the object belongs to.
TDI_QUERY_ADDRESS_INFO
The address information for the address object passed in.
TDI_QUERY_CONNECTION_INFO **NOT SUPPORTED**
The connection information for the connection object passed in.
TDI_QUERY_PROVIDER_STATISTICS **NOT SUPPORTED**
The provider statistics - per provider statistics. All actions on a particular
file object corresponds to activity on the provider of that file object. So each
provider context structure will have the provider statistics structure which will
be returned in this call.
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
PVOID pObject;
USHORT ObjectType;
USHORT DevType;
USHORT bufLen;
ULONG BytesWritten;
NTSTATUS status = STATUS_SUCCESS;
PTDI_REQUEST_KERNEL_QUERY_INFORMATION pQuery;
pObject = (PVOID)pIrpSp->FileObject->FsContext;
ObjectType = (USHORT)((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF);
DevType = (USHORT)((ULONG_PTR)(pIrpSp->FileObject->FsContext2) >> 16);
pQuery = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&pIrpSp->Parameters;
BytesWritten = 0;
pIrp->IoStatus.Information = 0;
bufLen = (USHORT)AtalkSizeMdlChain(pIrp->MdlAddress);
switch (pQuery->QueryType)
{
case TDI_QUERY_ADDRESS_INFO:
if (bufLen < sizeof(TDI_ADDRESS_INFO))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
switch (DevType)
{
case ATALK_DEV_DDP:
ASSERT(ObjectType == TDI_TRANSPORT_ADDRESS_FILE);
AtalkDdpQuery(pObject,
pIrp->MdlAddress,
&BytesWritten);
break;
case ATALK_DEV_PAP:
AtalkPapQuery(pObject,
ObjectType,
pIrp->MdlAddress,
&BytesWritten);
break;
case ATALK_DEV_ADSP:
AtalkAdspQuery(pObject,
ObjectType,
pIrp->MdlAddress,
&BytesWritten);
break;
case ATALK_DEV_ASPC:
case ATALK_DEV_ASP:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiQueryInformation: Invalid device type\n"));
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
case TDI_QUERY_CONNECTION_INFO:
// Statistics on a connection. Not supported.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiQueryInformation: TDI_QUERY_CONNECTION_INFO not supported\n"));
ASSERT(0);
status = STATUS_NOT_IMPLEMENTED;
break;
case TDI_QUERY_PROVIDER_INFO:
if (bufLen < sizeof(TDI_PROVIDER_INFO))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
status = TdiCopyBufferToMdl(&pCtx->adc_ProvInfo,
0,
sizeof (TDI_PROVIDER_INFO),
pIrp->MdlAddress,
0,
&BytesWritten);
break;
case TDI_QUERY_PROVIDER_STATISTICS:
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiQueryInformation: TDI_QUERY_PROVIDER_STATISTICS not supported\n"));
ASSERT(0);
status = STATUS_NOT_IMPLEMENTED;
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
pIrp->IoStatus.Information = BytesWritten;
return status;
}
NTSTATUS
AtalkTdiSetInformation(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status;
do
{
// Now depending on the requested device...
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
case ATALK_DEV_PAP:
case ATALK_DEV_ADSP:
case ATALK_DEV_ASPC:
status = STATUS_SUCCESS;
break;
case ATALK_DEV_ASP:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error. KeBugCheck.
status = STATUS_INVALID_DEVICE_REQUEST;
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiSetInformation: Invalid device type\n"));
break;
}
} while (FALSE);
return status;
}
NTSTATUS
AtalkTdiSetEventHandler(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN OUT PATALK_DEV_CTX pCtx
)
/*++
Routine Description:
This routine
Arguments:
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
PVOID pObject;
PDDP_ADDROBJ pDdpAddr;
PADSP_ADDROBJ pAdspAddr;
PPAP_ADDROBJ pPapAddr;
PASPC_ADDROBJ pAspAddr;
USHORT objectType;
USHORT devType;
KIRQL OldIrql;
NTSTATUS status = STATUS_SUCCESS;
do
{
PTDI_REQUEST_KERNEL_SET_EVENT parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&pIrpSp->Parameters;
pObject = (PVOID)pIrpSp->FileObject->FsContext;
objectType = (USHORT)((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF);
devType = (USHORT)((ULONG_PTR)(pIrpSp->FileObject->FsContext2) >> 16);
if (objectType != TDI_TRANSPORT_ADDRESS_FILE)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiSetEventHandler: returning STATUS_INVALID_ADDRESS\n"));
status = STATUS_INVALID_ADDRESS;
break;
}
switch (parameters->EventType)
{
case TDI_EVENT_RECEIVE_DATAGRAM:
if (devType != ATALK_DEV_DDP)
{
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
pDdpAddr = (PDDP_ADDROBJ)pObject;
if (!(VALID_DDP_ADDROBJ(pDdpAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, &OldIrql);
// Allocate event info if null.
if (pDdpAddr->ddpao_EventInfo == NULL)
{
pDdpAddr->ddpao_EventInfo =
AtalkAllocZeroedMemory(sizeof(DDPEVENT_INFO));
}
if (pDdpAddr->ddpao_EventInfo != NULL)
{
pDdpAddr->ddpao_Flags |= DDPAO_DGRAM_EVENT;
if ((pDdpAddr->ddpao_EventInfo->ev_RcvDgramHandler =
(PTDI_IND_RECEIVE_DATAGRAM)parameters->EventHandler) == NULL)
{
pDdpAddr->ddpao_Flags &= ~DDPAO_DGRAM_EVENT;
}
pDdpAddr->ddpao_EventInfo->ev_RcvDgramCtx = parameters->EventContext;
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
RELEASE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, OldIrql);
break;
case TDI_EVENT_ERROR:
break;
case TDI_EVENT_CONNECT:
switch (devType)
{
case ATALK_DEV_ADSP:
pAdspAddr = (PADSP_ADDROBJ)pObject;
if (!(VALID_ADSPAO(pAdspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
if (pAdspAddr->adspao_Flags & ADSPAO_CONNECT)
{
status = STATUS_INVALID_ADDRESS;
}
else
{
pAdspAddr->adspao_ConnHandler = (PTDI_IND_CONNECT)parameters->EventHandler;
pAdspAddr->adspao_ConnHandlerCtx = parameters->EventContext;
pAdspAddr->adspao_Flags |= ADSPAO_LISTENER;
}
RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
break;
case ATALK_DEV_PAP:
pPapAddr = (PPAP_ADDROBJ)pObject;
if (!(VALID_PAPAO(pPapAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
if (pPapAddr->papao_Flags & PAPAO_CONNECT)
{
status = STATUS_INVALID_ADDRESS;
}
else
{
pPapAddr->papao_Flags |= (PAPAO_LISTENER | PAPAO_UNBLOCKED);
// If we are setting a null handler, set it to blocked.
if ((pPapAddr->papao_ConnHandler = (PTDI_IND_CONNECT)parameters->EventHandler) == NULL)
{
// Oops. block. Dont care about listens being posted here.
pPapAddr->papao_Flags &= ~PAPAO_UNBLOCKED;
}
pPapAddr->papao_ConnHandlerCtx = parameters->EventContext;
}
RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
if (NT_SUCCESS(status))
{
// Prime the listener.
if (!ATALK_SUCCESS(AtalkPapPrimeListener(pPapAddr)))
{
TMPLOGERR();
}
}
break;
case ATALK_DEV_ASPC:
// No listens here. Client side only.
status = STATUS_INVALID_ADDRESS;
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
case TDI_EVENT_RECEIVE:
switch (devType)
{
case ATALK_DEV_ADSP:
pAdspAddr = (PADSP_ADDROBJ)pObject;
if (!(VALID_ADSPAO(pAdspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
pAdspAddr->adspao_RecvHandler = (PTDI_IND_RECEIVE)parameters->EventHandler;
pAdspAddr->adspao_RecvHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
break;
case ATALK_DEV_PAP:
pPapAddr = (PPAP_ADDROBJ)pObject;
if (!(VALID_PAPAO(pPapAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
pPapAddr->papao_RecvHandler = (PTDI_IND_RECEIVE)parameters->EventHandler;
pPapAddr->papao_RecvHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
break;
case ATALK_DEV_ASPC:
// No receives in asp client
status = STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
case TDI_EVENT_RECEIVE_EXPEDITED:
switch (devType)
{
case ATALK_DEV_ADSP:
pAdspAddr = (PADSP_ADDROBJ)pObject;
if (!(VALID_ADSPAO(pAdspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
pAdspAddr->adspao_ExpRecvHandler = (PTDI_IND_RECEIVE_EXPEDITED)parameters->EventHandler;
pAdspAddr->adspao_ExpRecvHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
break;
case ATALK_DEV_ASPC:
pAspAddr = (PASPC_ADDROBJ)pObject;
if (!(VALID_ASPCAO(pAspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAspAddr->aspcao_Lock, &OldIrql);
pAspAddr->aspcao_ExpRecvHandler = (PTDI_IND_RECEIVE_EXPEDITED)parameters->EventHandler;
pAspAddr->aspcao_ExpRecvHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pAspAddr->aspcao_Lock, OldIrql);
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
case TDI_EVENT_DISCONNECT:
switch (devType)
{
case ATALK_DEV_ADSP:
pAdspAddr = (PADSP_ADDROBJ)pObject;
if (!(VALID_ADSPAO(pAdspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
pAdspAddr->adspao_DisconnectHandler = (PTDI_IND_DISCONNECT)parameters->EventHandler;
pAdspAddr->adspao_DisconnectHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
break;
case ATALK_DEV_PAP:
pPapAddr = (PPAP_ADDROBJ)pObject;
if (!(VALID_PAPAO(pPapAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
pPapAddr->papao_DisconnectHandler = (PTDI_IND_DISCONNECT)parameters->EventHandler;
pPapAddr->papao_DisconnectHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
break;
case ATALK_DEV_ASPC:
pAspAddr = (PASPC_ADDROBJ)pObject;
if (!(VALID_ASPCAO(pAspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAspAddr->aspcao_Lock, &OldIrql);
pAspAddr->aspcao_DisconnectHandler = (PTDI_IND_DISCONNECT)parameters->EventHandler;
pAspAddr->aspcao_DisconnectHandlerCtx= parameters->EventContext;
RELEASE_SPIN_LOCK(&pAspAddr->aspcao_Lock, OldIrql);
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
case TDI_EVENT_SEND_POSSIBLE:
switch (devType)
{
case ATALK_DEV_ADSP:
pAdspAddr = (PADSP_ADDROBJ)pObject;
if (!(VALID_ADSPAO(pAdspAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pAdspAddr->adspao_Lock, &OldIrql);
pAdspAddr->adspao_SendPossibleHandler = (PTDI_IND_SEND_POSSIBLE)parameters->EventHandler;
pAdspAddr->adspao_SendPossibleHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pAdspAddr->adspao_Lock, OldIrql);
break;
case ATALK_DEV_PAP:
pPapAddr = (PPAP_ADDROBJ)pObject;
if (!(VALID_PAPAO(pPapAddr)))
{
ASSERT(0);
status = STATUS_INVALID_ADDRESS;
break;
}
ACQUIRE_SPIN_LOCK(&pPapAddr->papao_Lock, &OldIrql);
pPapAddr->papao_SendPossibleHandler = (PTDI_IND_SEND_POSSIBLE)parameters->EventHandler;
pPapAddr->papao_SendPossibleHandlerCtx = parameters->EventContext;
RELEASE_SPIN_LOCK(&pPapAddr->papao_Lock, OldIrql);
break;
case ATALK_DEV_ASPC:
// No sends in asp client
status = STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
default:
status = STATUS_INVALID_PARAMETER;
}
#if DBG
// Avoid assertions in AFD.
status = STATUS_SUCCESS;
#endif
} while (FALSE);
return status;
}
VOID
AtalkTdiCancel(
IN OUT PATALK_DEV_OBJ pDevObj,
IN PIRP pIrp
)
/*++
Routine Description:
This routine handles cancellation of IO requests
Arguments:
Return Value:
--*/
{
PIO_STACK_LOCATION pIrpSp;
PVOID pObject;
PATALK_DEV_CTX pCtx;
PVOID FsContext2;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pObject = pIrpSp->FileObject->FsContext;
FsContext2 = pIrpSp->FileObject->FsContext2;
pCtx = &pDevObj->Ctx;
ASSERT(((LONG_PTR)FsContext2 >> 16) == pCtx->adc_DevType);
IoReleaseCancelSpinLock (pIrp->CancelIrql);
switch (pCtx->adc_DevType)
{
case ATALK_DEV_DDP:
break;
case ATALK_DEV_ASPC:
if (FsContext2 == (PVOID)((ULONG_PTR)(TDI_CONNECTION_FILE + (pCtx->adc_DevType << 16))))
{
AtalkAspCCleanupConnection((PASPC_CONNOBJ)pObject);
}
else
{
AtalkAspCCleanupAddress((PASPC_ADDROBJ)pObject);
}
break;
case ATALK_DEV_ASP:
// We only handle cancellation of IO requests on connection objects.
if (FsContext2 == (PVOID)((ULONG_PTR)(TDI_CONNECTION_FILE + (pCtx->adc_DevType << 16))))
AtalkAspCleanupConnection((PASP_CONNOBJ)pObject);
break;
case ATALK_DEV_PAP:
if (FsContext2 == (PVOID)((ULONG_PTR)(TDI_CONNECTION_FILE + (pCtx->adc_DevType << 16))))
{
AtalkPapCleanupConnection((PPAP_CONNOBJ)pObject);
}
else
{
AtalkPapCleanupAddress((PPAP_ADDROBJ)pObject);
}
break;
case ATALK_DEV_ADSP:
if (FsContext2 == (PVOID)((ULONG_PTR)(TDI_CONNECTION_FILE + (pCtx->adc_DevType << 16))))
AtalkAdspCleanupConnection((PADSP_CONNOBJ)pObject);
else AtalkAdspCleanupAddress((PADSP_ADDROBJ)pObject);
break;
case ATALK_DEV_ARAP:
ArapCancelIrp(pIrp);
break;
default:
// The device type in the Ctx field can never be anything
// other than the above! Internal protocol error.
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("AtalkTdiCancel: Invalid device type\n"));
break;
}
}
VOID
AtalkQueryInitProviderInfo(
IN ATALK_DEV_TYPE DeviceType,
IN OUT PTDI_PROVIDER_INFO ProviderInfo
)
{
//
// Initialize to defaults first
//
RtlZeroMemory((PVOID)ProviderInfo, sizeof(TDI_PROVIDER_INFO));
ProviderInfo->Version = ATALK_TDI_PROVIDERINFO_VERSION;
KeQuerySystemTime (&ProviderInfo->StartTime);
switch (DeviceType)
{
case ATALK_DEV_DDP:
ProviderInfo->MaxDatagramSize = ATALK_DDP_PINFODGRAMSIZE;
ProviderInfo->ServiceFlags = ATALK_DDP_PINFOSERVICEFLAGS;
break;
case ATALK_DEV_PAP:
ProviderInfo->MaxSendSize = ATALK_PAP_PINFOSENDSIZE;
ProviderInfo->ServiceFlags = ATALK_PAP_PINFOSERVICEFLAGS;
break;
case ATALK_DEV_ADSP:
ProviderInfo->MaxSendSize = ATALK_ADSP_PINFOSENDSIZE;
ProviderInfo->ServiceFlags = ATALK_ADSP_PINFOSERVICEFLAGS;
break;
case ATALK_DEV_ASP:
ProviderInfo->MaxSendSize = ATALK_ASP_PINFOSENDSIZE;
ProviderInfo->ServiceFlags = ATALK_ASP_PINFOSERVICEFLAGS;
break;
case ATALK_DEV_ARAP:
ProviderInfo->MaxSendSize = ATALK_ARAP_PINFOSENDSIZE;
ProviderInfo->ServiceFlags = ATALK_ARAP_PINFOSERVICEFLAGS;
break;
case ATALK_DEV_ASPC:
ProviderInfo->MaxSendSize = ATALK_ASP_PINFOSENDSIZE;
ProviderInfo->ServiceFlags = ATALK_ASP_PINFOSERVICEFLAGS;
break;
default:
KeBugCheck(0);
}
}
LOCAL VOID FASTCALL
atalkTdiSendDgramComplete(
IN NDIS_STATUS Status,
IN PSEND_COMPL_INFO pSendInfo
)
{
PDDP_ADDROBJ pAddr = (PDDP_ADDROBJ)(pSendInfo->sc_Ctx1);
PBUFFER_DESC pBufDesc = (PBUFFER_DESC)(pSendInfo->sc_Ctx2);
PIRP pIrp = (PIRP)(pSendInfo->sc_Ctx3);
ASSERT(VALID_DDP_ADDROBJ(pAddr));
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("atalkTdiSendDgramComplete: Status %lx, addr %lx\n", Status, pAddr));
AtalkFreeBuffDesc(pBufDesc);
pIrp->CancelRoutine = NULL;
TdiCompleteRequest(pIrp,
((Status == NDIS_STATUS_SUCCESS) ?
STATUS_SUCCESS: STATUS_UNSUCCESSFUL));
}
LOCAL VOID
atalkTdiRecvDgramComplete(
IN ATALK_ERROR ErrorCode,
IN PAMDL pReadBuf,
IN USHORT ReadLen,
IN PATALK_ADDR pSrcAddr,
IN PIRP pIrp
)
{
PIO_STACK_LOCATION pIrpSp;
PTDI_REQUEST_KERNEL_RECEIVEDG parameters;
PTDI_CONNECTION_INFORMATION returnInfo;
PTA_APPLETALK_ADDRESS remoteAddress;
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("atalkTdiRecvDgramComplete: %lx\n", ErrorCode));
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
parameters = (PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters;
// Set length in the info field and call the completion routine.
pIrp->CancelRoutine = NULL;
pIrp->IoStatus.Information = (ULONG)ReadLen;
if (ATALK_SUCCESS(ErrorCode))
{
ASSERT(parameters != NULL);
if (parameters != NULL)
{
parameters->ReceiveLength = (ULONG)ReadLen;
try {
returnInfo =
(PTDI_CONNECTION_INFORMATION)parameters->ReturnDatagramInformation;
ASSERT(returnInfo != NULL);
if (returnInfo != NULL)
{
if (returnInfo->RemoteAddressLength >= sizeof(TA_APPLETALK_ADDRESS))
{
// Fill in the remote address
remoteAddress = (PTA_APPLETALK_ADDRESS)returnInfo->RemoteAddress;
ASSERT(remoteAddress != NULL);
if (remoteAddress != NULL)
{
// Copy the remote address from where the datagram was received
ATALKADDR_TO_TDI(
remoteAddress,
pSrcAddr);
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_ERR,
("AtalkAddrRecvDgComp - Net %x Node %x Socket %x\n",
remoteAddress->Address[0].Address[0].Network,
remoteAddress->Address[0].Address[0].Node,
remoteAddress->Address[0].Address[0].Socket));
}
}
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
ErrorCode = GetExceptionCode();
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("atalkTdiRecvDgramComplete: exception occured %lx\n", ErrorCode));
}
}
}
ASSERT (ErrorCode != ATALK_PENDING);
TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
}
LOCAL VOID
atalkTdiActionComplete(
IN ATALK_ERROR ErrorCode,
IN PACTREQ pActReq
)
{
PIRP pIrp = pActReq->ar_pIrp;
ASSERT (VALID_ACTREQ(pActReq));
if (pActReq->ar_pAMdl != NULL)
AtalkFreeAMdl(pActReq->ar_pAMdl);
AtalkFreeMemory(pActReq);
pIrp->CancelRoutine = NULL;
ASSERT (ErrorCode != ATALK_PENDING);
TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
}
LOCAL VOID
atalkTdiGenericComplete(
IN ATALK_ERROR ErrorCode,
IN PIRP pIrp
)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("atalkTdiGenericComplete: Completing %lx with %lx\n",
pIrp, AtalkErrorToNtStatus(ErrorCode)));
pIrp->CancelRoutine = NULL;
ASSERT (ErrorCode != ATALK_PENDING);
TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
}
LOCAL VOID
atalkTdiCloseAddressComplete(
IN ATALK_ERROR ErrorCode,
IN PIRP pIrp
)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("atalkTdiCloseAddressComplete: Completing %lx with %lx\n",
pIrp, AtalkErrorToNtStatus(ErrorCode)));
pIrp->CancelRoutine = NULL;
ASSERT (ErrorCode != ATALK_PENDING);
AtalkUnlockTdiIfNecessary();
TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
}
LOCAL VOID
atalkTdiGenericReadComplete(
IN ATALK_ERROR ErrorCode,
IN PAMDL ReadBuf,
IN USHORT ReadLen,
IN ULONG ReadFlags,
IN PIRP pIrp
)
{
ASSERT(pIrp->IoStatus.Status != STATUS_UNSUCCESSFUL);
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("atalkTdiGenericReadComplete: Irp %lx Status %lx Info %lx\n",
pIrp, pIrp->IoStatus.Status, ReadLen));
pIrp->CancelRoutine = NULL;
pIrp->IoStatus.Information = (ULONG)ReadLen;
ASSERT (ErrorCode != ATALK_PENDING);
TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
}
VOID
atalkTdiGenericWriteComplete(
IN ATALK_ERROR ErrorCode,
IN PAMDL WriteBuf,
IN USHORT WriteLen,
IN PIRP pIrp
)
{
ASSERT(pIrp->IoStatus.Status != STATUS_UNSUCCESSFUL);
if (pIrp->IoStatus.Status == STATUS_UNSUCCESSFUL)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_ERR,
("atalkTdiGenericWriteComplete: Irp %lx Status %lx Info %lx\n",
pIrp, pIrp->IoStatus.Status, WriteLen));
}
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_INFO,
("atalkTdiGenericWriteComplete: Irp %lx Status %lx Info %lx\n",
pIrp, pIrp->IoStatus.Status, WriteLen));
pIrp->CancelRoutine = NULL;
pIrp->IoStatus.Information = (ULONG)WriteLen;
ASSERT (ErrorCode != ATALK_PENDING);
TdiCompleteRequest(pIrp, AtalkErrorToNtStatus(ErrorCode));
}
LOCAL VOID
atalkQueuedLockUnlock(
IN PQLU pQLU
)
{
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
AtalkLockUnlock(FALSE,
pQLU->qlu_pLockSection);
AtalkPortDereference(pQLU->qlu_pPortDesc);
AtalkFreeMemory(pQLU);
}
VOID
AtalkLockInit(
IN PLOCK_SECTION pLs,
IN PVOID Address
)
{
pLs->ls_LockHandle = MmLockPagableCodeSection(Address);
MmUnlockPagableImageSection(pLs->ls_LockHandle);
}
VOID
AtalkLockUnlock(
IN BOOLEAN Lock,
IN PLOCK_SECTION pLs
)
{
KIRQL OldIrql;
BOOLEAN DoForReal;
// We cannot call the MmLock/MmUnlock routines at Dpc. So if we are called at
// DISPATCH, just queue ourselves. Also we only get unlock requests at DISPATCH,
// Lock requests are only at LOW_LEVEL. So failure to allocate memory can be
// IGNORED since that will only have the effect of failure to unlock.
if (KeGetCurrentIrql() == DISPATCH_LEVEL)
{
PQLU pQLU;
ATALK_ERROR Error;
ASSERT (!Lock || (pLs->ls_LockCount > 0));
if (Lock)
{
ASSERT (pLs->ls_LockCount > 0);
ACQUIRE_SPIN_LOCK_DPC(&AtalkPgLkLock);
pLs->ls_LockCount ++;
RELEASE_SPIN_LOCK_DPC(&AtalkPgLkLock);
}
else
{
if ((pQLU = AtalkAllocMemory(sizeof(QLU))) != NULL)
{
pQLU->qlu_pPortDesc = AtalkPortList;
AtalkPortReferenceByPtrDpc(pQLU->qlu_pPortDesc, &Error);
if (ATALK_SUCCESS(Error))
{
pQLU->qlu_pLockSection = pLs;
ExInitializeWorkItem(&pQLU->qlu_WQI, atalkQueuedLockUnlock, pQLU);
ExQueueWorkItem(&pQLU->qlu_WQI, CriticalWorkQueue);
}
else
{
AtalkFreeMemory(pQLU);
}
}
}
return;
}
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
// We need to serialize the operations here. Note that a spin-lock will not do the
// job since the MmLock/MmUnlock routines cannot be called with the spin-lock held
KeWaitForSingleObject(&AtalkPgLkMutex,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL);
ASSERT (pLs->ls_LockHandle != NULL);
DoForReal = FALSE;
ACQUIRE_SPIN_LOCK(&AtalkPgLkLock, &OldIrql);
if (Lock)
{
if (pLs->ls_LockCount == 0)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_WARN,
("AtalkLockUnlock: Locking %d\n", pLs - AtalkPgLkSection));
DoForReal = TRUE;
}
pLs->ls_LockCount ++;
}
else
{
ASSERT (pLs->ls_LockCount > 0);
pLs->ls_LockCount --;
if (pLs->ls_LockCount == 0)
{
DBGPRINT(DBG_COMP_TDI, DBG_LEVEL_WARN,
("AtalkLockUnlock: Unlocking %d\n", pLs - AtalkPgLkSection));
DoForReal = TRUE;
}
}
RELEASE_SPIN_LOCK(&AtalkPgLkLock, OldIrql);
if (DoForReal)
{
if (Lock)
{
MmLockPagableSectionByHandle(pLs->ls_LockHandle);
}
else
{
MmUnlockPagableImageSection(pLs->ls_LockHandle);
}
}
// LeaveCriticalSection
KeReleaseMutex(&AtalkPgLkMutex, FALSE);
}
VOID
atalkWaitDefaultPort(
VOID
)
{
TIME Time;
#define ONE_SEC_IN_100ns -10000000L // 1sec in 100ns units
if ((AtalkDefaultPort == NULL) ||
((AtalkDefaultPort->pd_Flags & (PD_USER_NODE_1 | PD_USER_NODE_2)) == 0))
{
// Make sure we can indeed wait
ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
Time.QuadPart = Int32x32To64((LONG)20, ONE_SEC_IN_100ns);
KeWaitForSingleObject(&AtalkDefaultPortEvent, Executive, KernelMode, FALSE, &Time);
}
}