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
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);
|
|
}
|
|
}
|
|
|
|
|
|
|