Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2411 lines
61 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
mainint.c
Abstract:
This module contains the TDI interface code supporting the primary tdi
calls
Author:
Nikhil Kamkolkar (NikhilK) 28-Jun-1992
Revision History:
--*/
#include "atalknt.h"
#include "mainint.h"
#include "aspint.h"
//
// Define the Action dispatch table here.
//
// *IMPORTANT*
// This table is tightly integrated with the action codes defined in
// ATKTDI.H.
//
// Order is NBP/ZIP/ADSP/ATP/ASP/PAP
//
// Each element of the array contains:
// _MinBufLen - The minimum length of the MdlAddress buffer for the request
// _OpCode - The action code of the request (sanity check)
// _OpInfo - Bit flags give more information about the request
// DFLAG_CONNECTION - Object for request must be connection object
// DFLAG_CONTROLCHANNEL - Object for request must be control channel
// DFLAG_ADDRESS - Object for request must be an address object
// DFLAG_MDL1 - Request uses an mdl (submdl of MdlAddress)
// DFLAG_MDL2 - Request uses a second mdl (submdl of MdlAddress)
// DFLAG_MDL3 - Request uses a third mdl (submdl of MdlAddress)
// _ActionBufSize - The size of the action header buffer for request
// (beginning of the buffer described by MdlAddress)
// _DeviceType - Valid device types for the request
// ATALK_DEVICE_ANY => Any device except APPLETALK
// _MdlSize1Offset - Offset in action buffer where the size for the first
// mdl can be found. Non-zero only when DFLAG_MDL2 is set.
// _MdlSize2Offset - Offset in action buffer where the size for the second
// mdl can be found. Non-zero only when DFLAG_MDL3 is set.
// _Dispatch - The dispatch routine for the request
// _Completion - The completion routine for the request (NULL if sync)
//
struct _ActionDispatch {
ULONG _MinBufLen;
ULONG _OpCode;
ULONG _OpInfo;
ULONG _ActionBufSize;
ATALK_DEVICE_TYPE _DeviceType;
ULONG _MdlSizeOffset[MAX_REQUESTMDLS-1];
APIWORKER _Dispatch;
PVOID _Completion;
} ActionDispatch[MAX_ALLACTIONCODES+1] =
{
//
// NBP dispatch functions
//
{
sizeof(NBP_LOOKUP_ACTION),
COMMON_ACTION_NBPLOOKUP,
(DFLAG_CONTROLCHANNEL | DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(NBP_LOOKUP_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionNbp,
NTNbpGenericComplete
},
{
sizeof(NBP_CONFIRM_ACTION),
COMMON_ACTION_NBPCONFIRM,
(DFLAG_CONTROLCHANNEL | DFLAG_ADDRESS),
sizeof(NBP_CONFIRM_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionNbp,
NTNbpGenericComplete
},
{
sizeof(NBP_REGDEREG_ACTION),
COMMON_ACTION_NBPREGISTER,
DFLAG_ADDRESS,
sizeof(NBP_REGDEREG_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionNbp,
NTNbpGenericComplete
},
{
sizeof(NBP_REGDEREG_ACTION),
COMMON_ACTION_NBPREMOVE,
DFLAG_ADDRESS,
sizeof(NBP_REGDEREG_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionNbp,
NULL
},
//
// ZIP dispatch functions
//
{
sizeof(ZIP_GETMYZONE_ACTION),
COMMON_ACTION_ZIPGETMYZONE,
(DFLAG_CONTROLCHANNEL | DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ZIP_GETMYZONE_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionZip,
NTZipGetMyZoneComplete
},
{
sizeof(ZIP_GETZONELIST_ACTION),
COMMON_ACTION_ZIPGETZONELIST,
(DFLAG_CONTROLCHANNEL | DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ZIP_GETZONELIST_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionZip,
NTZipGetZonesComplete
},
{
sizeof(ZIP_GETZONELIST_ACTION),
COMMON_ACTION_ZIPGETLZONES,
(DFLAG_CONTROLCHANNEL | DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ZIP_GETZONELIST_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionZip,
NTZipGetZonesComplete
},
{
sizeof(ZIP_GETZONELIST_ACTION),
COMMON_ACTION_ZIPGETLZONESONADAPTER,
(DFLAG_CONTROLCHANNEL | DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ZIP_GETZONELIST_ACTION),
ATALK_DEVICE_ANY,
{0,
0},
AtalkTdiActionZip,
NTZipGetZonesComplete
},
//
// ADSP dispatch functions
//
{
sizeof(ADSP_FORWARDRESET_ACTION),
ACTION_ADSPFORWARDRESET,
(DFLAG_CONNECTION),
sizeof(ADSP_FORWARDRESET_ACTION),
ATALK_DEVICE_ADSP,
{0,
0},
AtalkTdiActionAdsp,
NULL
},
//
// ATP Dispatch functions
//
{
sizeof(ATP_POSTREQ_ACTION),
ACTION_ATPPOSTREQ,
(DFLAG_ADDRESS | DFLAG_MDL1 | DFLAG_MDL2),
sizeof(ATP_POSTREQ_ACTION),
ATALK_DEVICE_ATP,
{FIELD_OFFSET(ATP_POSTREQ_ACTION, Params.RequestBufLen),
0},
AtalkTdiActionAtp,
NTAtpPostRequestComplete
},
{
sizeof(ATP_POSTREQCANCEL_ACTION),
ACTION_ATPPOSTREQCANCEL,
(DFLAG_ADDRESS),
sizeof(ATP_POSTREQCANCEL_ACTION),
ATALK_DEVICE_ATP,
{0,
0},
AtalkTdiActionAtp,
NULL
},
{
sizeof(ATP_GETREQ_ACTION),
ACTION_ATPGETREQ,
(DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ATP_GETREQ_ACTION),
ATALK_DEVICE_ATP,
{0,
0},
AtalkTdiActionAtp,
NTAtpGetRequestComplete
},
{
sizeof(ATP_GETREQCANCEL_ACTION),
ACTION_ATPGETREQCANCEL,
(DFLAG_ADDRESS),
sizeof(ATP_GETREQCANCEL_ACTION),
ATALK_DEVICE_ATP,
{0,
0},
AtalkTdiActionAtp,
NULL
},
{
sizeof(ATP_POSTRESP_ACTION),
ACTION_ATPPOSTRESP,
(DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ATP_POSTRESP_ACTION),
ATALK_DEVICE_ATP,
{0,
0},
AtalkTdiActionAtp,
NTAtpPostResponseComplete
},
{
sizeof(ATP_POSTRESPCANCEL_ACTION),
ACTION_ATPPOSTRESPCANCEL,
(DFLAG_ADDRESS),
sizeof(ATP_POSTRESPCANCEL_ACTION),
ATALK_DEVICE_ATP,
{0,
0},
AtalkTdiActionAtp,
NULL
},
//
// ASP Dispatch functions
//
{
sizeof(ASP_GETREQ_ACTION),
ACTION_ASPGETREQ,
(DFLAG_CONNECTION | DFLAG_MDL1),
sizeof(ASP_GETREQ_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NTAspGetRequestComplete
},
{
sizeof(ASP_GETANYREQ_ACTION),
ACTION_ASPGETANYREQ,
(DFLAG_ADDRESS),
sizeof(ASP_GETANYREQ_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NTAspGetAnyRequestComplete
},
{
sizeof(ASP_COMMAND_ACTION),
ACTION_ASPCOMMAND,
(DFLAG_CONNECTION | DFLAG_MDL1 | DFLAG_MDL2),
sizeof(ASP_COMMAND_ACTION),
ATALK_DEVICE_ASP,
{FIELD_OFFSET(ASP_COMMAND_ACTION, Params.CommandBufLen),
0},
AtalkTdiActionAsp,
NTAspCommandComplete
},
{
sizeof(ASP_REPLY_ACTION),
ACTION_ASPREPLY,
(DFLAG_CONNECTION | DFLAG_MDL1),
sizeof(ASP_REPLY_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NTAspReplyComplete
},
{
sizeof(ASP_WRITE_ACTION),
ACTION_ASPWRITE,
(DFLAG_CONNECTION | DFLAG_MDL1 | DFLAG_MDL2 | DFLAG_MDL3),
sizeof(ASP_WRITE_ACTION),
ATALK_DEVICE_ASP,
{FIELD_OFFSET(ASP_WRITE_ACTION, Params.CommandBufLen),
FIELD_OFFSET(ASP_WRITE_ACTION, Params.WriteBufLen)},
AtalkTdiActionAsp,
NTAspWriteComplete
},
{
sizeof(ASP_WRITECONT_ACTION),
ACTION_ASPWRITECONT,
(DFLAG_CONNECTION | DFLAG_MDL1),
sizeof(ASP_WRITECONT_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NTAspWriteContinueComplete
},
{
sizeof(ASP_ATTENTION_ACTION),
ACTION_ASPGETATTN,
(DFLAG_CONNECTION),
sizeof(ASP_ATTENTION_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NTAspGetAttentionComplete
},
{
sizeof(ASP_ATTENTION_ACTION),
ACTION_ASPSENDATTN,
(DFLAG_CONNECTION),
sizeof(ASP_ATTENTION_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NULL
},
{
sizeof(ASP_GETSTATUS_ACTION),
ACTION_ASPGETSTATUS,
(DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ASP_GETSTATUS_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NTAspGetStatusComplete
},
{
sizeof(ASP_SETSTATUS_ACTION),
ACTION_ASPSETSTATUS,
(DFLAG_ADDRESS | DFLAG_MDL1),
sizeof(ASP_SETSTATUS_ACTION),
ATALK_DEVICE_ASP,
{0,
0},
AtalkTdiActionAsp,
NULL
},
//
// PAP dispatch routines
//
{
sizeof(PAP_GETSTATUSSRV_ACTION),
ACTION_PAPGETSTATUSSRV,
(DFLAG_ADDRESS | DFLAG_CONTROLCHANNEL | DFLAG_MDL1),
sizeof(PAP_GETSTATUSSRV_ACTION),
ATALK_DEVICE_PAP,
{0,
0},
AtalkTdiActionPap,
NTPapGetStatusComplete
},
{
sizeof(PAP_GETSTATUSJOB_ACTION),
ACTION_PAPGETSTATUSJOB,
(DFLAG_CONNECTION | DFLAG_MDL1),
sizeof(PAP_GETSTATUSJOB_ACTION),
ATALK_DEVICE_PAP,
{0,
0},
AtalkTdiActionPap,
NTPapGetStatusComplete
},
{
sizeof(PAP_SETSTATUS_ACTION),
ACTION_PAPSETSTATUS,
(DFLAG_ADDRESS | DFLAG_CONTROLCHANNEL | DFLAG_MDL1),
sizeof(PAP_SETSTATUS_ACTION),
ATALK_DEVICE_PAP,
{0,
0},
AtalkTdiActionPap,
NULL
}
};
//
// Primary TDI Functions for appletalk stack
//
NTSTATUS
AtalkTdiOpenAddress(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
PTA_APPLETALK_ADDRESS TdiAddress,
PIO_SECURITY_CONTEXT SecurityContext,
ULONG ShareAccess,
UCHAR ProtocolType,
UCHAR SocketType,
PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine is used to create an address object. It will also the
create the appropriate socket with the portable stack.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
TdiAddress - The Appletalk address to be used
TdiAddressLength - Length of above address
SecurityContext - Security context to associate with object (ignored)
ShareAccess - Share access to be associated with object (ignored)
Context - The DeviceContext of the device on which open is happening
Return Value:
STATUS_SUCCESS if address was successfully opened
Error otherwise.
--*/
{
NTSTATUS status;
//
// Preliminary checks
// If address type/size are invalid, return
//
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiOpenAddress:\nNet %x Node %x Socket %x\n",
TdiAddress->Address[0].Address[0].Network,
TdiAddress->Address[0].Address[0].Node,
TdiAddress->Address[0].Address[0].Socket));
if ((TdiAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_APPLETALK) &&
(TdiAddress->Address[0].AddressLength == sizeof(TDI_ADDRESS_APPLETALK))) {
status = AtalkCreateAddress(
TdiAddress,
(PADDRESS_FILE *)&FileObject->FsContext,
ProtocolType,
SocketType,
Context);
} else {
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiOpenAddress - Type %x\n Len %d\n",
TdiAddress->Address[0].AddressType,
TdiAddress->Address[0].AddressLength));
status = STATUS_INVALID_ADDRESS;
}
if (NT_SUCCESS(status)) {
FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
} else {
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiOpenAddress - Create error %lx\n", status));
}
return(status);
}
NTSTATUS
AtalkTdiOpenConnection(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
CONNECTION_CONTEXT ConnectionContext,
PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine is used to create a connection object and associate the
passed ConnectionContext with it.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
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.
--*/
{
NTSTATUS status;
status = AtalkCreateConnection(
ConnectionContext,
(PCONNECTION_FILE *)&FileObject->FsContext,
Context);
if (NT_SUCCESS(status)) {
FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
} else {
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCreateConnection - failed %lx\n",status));
}
return(status);
}
NTSTATUS
AtalkTdiOpenControlChannel(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine is used to create a control channel
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
Context - The DeviceContext of the device on which open is happening
Return Value:
STATUS_SUCCESS if controlchannel was successfully opened
Error otherwise.
--*/
{
NTSTATUS status;
status = AtalkCreateControlChannel(
(PCONTROLCHANNEL_FILE *)&FileObject->FsContext,
Context);
if (NT_SUCCESS(status)) {
FileObject->FsContext2 = (PVOID)ATALK_FILE_TYPE_CONTROL;
} else {
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCreateControlChannel - failed %lx\n",status));
}
return(status);
}
NTSTATUS
AtalkTdiCleanupAddress(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine is used to prepare the address for closing.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
Irp - The cleanup irp
Context - The DeviceContext of the device on which cleanup is happening
Return Value:
STATUS_SUCCESS if stop Address started successfully
Error otherwise.
--*/
{
NTSTATUS status;
PADDRESS_FILE address;
//
// Verify the address, if valid call AtalkCleanupAddress
//
address = (PADDRESS_FILE)FileObject->FsContext;
AtalkVerifyIsAddressObject(status,address,FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Verify provider types are the same
//
if (Context->DeviceType == address->OwningDevice) {
status = AtalkCleanupAddress(
IoStatus,
address,
Irp,
Context);
} else {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiCleanup - Providers not the same %lx\n", address));
ASSERT(0);
}
//
// This removes a reference during the Verify
//
AtalkDereferenceAddress ("ClosingAddr", address, \
AREF_VERIFY, SECONDARY_REFSET);
}
return(status);
}
NTSTATUS
AtalkTdiCleanupConnection(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine is used to prepare the connection for closing.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
Irp - The cleanup irp
Context - The DeviceContext of the device on which cleanup is happening
Return Value:
STATUS_SUCCESS if stop connection started successfully
Error otherwise.
--*/
{
NTSTATUS status;
PCONNECTION_FILE connection;
//
// Verify the connection object
//
connection = (PCONNECTION_FILE)FileObject->FsContext;
AtalkVerifyIsConnectionObject(status,connection, FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Verify provider types are the same
// Should this be an ASSERT() instead?
//
if (Context->DeviceType == connection->OwningDevice) {
status = AtalkCleanupConnection(
IoStatus,
connection,
Irp,
Context);
} else {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiCleanup - Providers not the same %lx\n", connection));
ASSERT(0);
}
//
// This removes a reference added during the Verify
//
AtalkDereferenceConnection ("ConnClosing", connection, \
CREF_VERIFY, SECONDARY_REFSET);
}
return(status);
}
NTSTATUS
AtalkTdiCloseAddress(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closeIrp for completion.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
Irp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
NTSTATUS status;
PADDRESS_FILE address;
//
// Verify the address, if valid call AtalkCloseAddress
//
address = (PADDRESS_FILE)FileObject->FsContext;
AtalkVerifyIsAddressObject(status,address, FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Verify provider types are the same
//
if (Context->DeviceType == address->OwningDevice) {
status = AtalkCloseAddress(
IoStatus,
address,
Irp,
Context);
} else {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiCleanup - Providers not the same %lx\n", address));
ASSERT(0);
}
//
// This removes a reference during the Verify
//
AtalkDereferenceAddress ("ClosingAddr", address, \
AREF_VERIFY, SECONDARY_REFSET);
}
return(status);
}
NTSTATUS
AtalkTdiCloseConnection(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closeIrp for completion.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
Irp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
NTSTATUS status;
PCONNECTION_FILE connection;
//
// Verify the connection object
//
connection = (PCONNECTION_FILE)FileObject->FsContext;
AtalkVerifyIsConnectionObject(status,connection, FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Verify provider types are the same
//
if (Context->DeviceType == connection->OwningDevice) {
status = AtalkCloseConnection(
IoStatus,
connection,
Irp,
Context);
} else {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiClose - Providers not the same %lx\n", connection));
ASSERT(0);
}
//
// This removes a reference added during the Verify
//
AtalkDereferenceConnection ("ConnClosing", connection, \
CREF_VERIFY, SECONDARY_REFSET);
}
return(status);
}
NTSTATUS
AtalkTdiCloseControlChannel(
PIO_STATUS_BLOCK IoStatus,
PFILE_OBJECT FileObject,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine removes the creation reference on the object. It also
sets up the closeIrp for completion.
Arguments:
IoStatus - Pointer to the iostatus block in the irp
FileObject - Pointer to the filesystem fileobject passed in irp
Irp - The close irp
Context - The DeviceContext of the device on which close is happening
Return Value:
STATUS_SUCCESS if successfully setup
Error otherwise.
--*/
{
NTSTATUS status;
PCONTROLCHANNEL_FILE controlChannel;
//
// Verify the cc object
//
controlChannel = (PCONTROLCHANNEL_FILE)FileObject->FsContext;
AtalkVerifyIsControlChannelObject(status,controlChannel, FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Verify provider types are the same
//
if (Context->DeviceType == controlChannel->OwningDevice) {
status = AtalkCloseControlChannel(
IoStatus,
controlChannel,
Irp,
Context);
} else {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiClose - Providers not the same %lx\n", controlChannel));
ASSERT(0);
}
//
// This removes a reference added during the Verify
//
AtalkDereferenceControlChannel ("ConChClosing", controlChannel, \
CCREF_VERIFY, SECONDARY_REFSET);
}
return(status);
}
NTSTATUS
AtalkTdiAssociateAddress(
IN PATALK_TDI_REQUEST Request
)
/*++
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:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
PCONNECTION_FILE connection =
(PCONNECTION_FILE)Request->FileObject->FsContext;
PTDI_REQUEST_KERNEL_ASSOCIATE parameters =
(PTDI_REQUEST_KERNEL_ASSOCIATE)Request->Parameters;
PFILE_OBJECT addressFileObject;
PADDRESS_FILE address;
if (NT_SUCCESS(status)) {
//
// get a pointer to the address File Object, which points us to the
// transport's address object, which is where we want to put the
// connection.
//
status = ObReferenceObjectByHandle (
parameters->AddressHandle,
0L,
0,
KernelMode,
(PVOID *) &addressFileObject,
NULL);
if (NT_SUCCESS(status)) {
//
// We should have one of our address objects; verify that.
// This also references it once
//
address = (PADDRESS_FILE)addressFileObject->FsContext;
AtalkVerifyIsAddressObject(status,address, addressFileObject->FsContext2);
if (NT_SUCCESS (status)) {
//
// Verify that the provider names are all the same
//
if ((address->OwningDevice == connection->OwningDevice) &&
(address->OwningDevice == Request->DeviceContext->DeviceType)) {
status = AtalkConnAssociateAddress(
connection,
address);
} else {
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAssociate - Providers not the same\n"));
ASSERT(0);
status = STATUS_NO_SUCH_DEVICE;
}
//
// Dereference the address
//
AtalkDereferenceAddress("AddrAssoc", address,
AREF_VERIFY, SECONDARY_REFSET);
} else {
status = STATUS_INVALID_HANDLE;
}
//
// Note that we don't keep a reference to this file object around.
// That's because the IO subsystem manages the object for us; we simply
// want to keep the association. We only use this association when the
// IO subsystem has asked us to close one of the file object, and then
// we simply remove the association.
//
ObDereferenceObject (addressFileObject);
} else {
status = STATUS_INVALID_HANDLE;
}
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAssociate - complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiDisassociateAddress(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine performs a disassociate. This request is only valid when
the connection is in a purely ASSOCIATED state.
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
if (NT_SUCCESS(status)) {
//
// This will never return STATUS_PENDING
//
status = AtalkConnDisassociateAddress(
(PCONNECTION_FILE)Request->FileObject->FsContext);
ASSERT(status != STATUS_PENDING);
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiDisassociate - complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiConnect(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine will post a connect request with the portable stack.
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
PCONNECTION_FILE connection = (PCONNECTION_FILE)Request->FileObject->FsContext;
if (NT_SUCCESS(status)) {
//
// Now verify the associated address object
//
status = AtalkConnVerifyAssocAddress(connection);
if (NT_SUCCESS(status)) {
status = AtalkConnPostConnect(
connection,
Request);
//
// Deference the address, connection reference goes during completion
//
AtalkConnDereferenceAssocAddress(connection);
}
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiConnect - Complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiDisconnect(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine will disconnect an active connection or cancel a posted
listen/connect
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
if (NT_SUCCESS(status)) {
status = AtalkConnPostDisconnect(
(PCONNECTION_FILE)Request->FileObject->FsContext,
Request);
if (status == STATUS_PENDING) {
//
// Hmmm, the higher layers will not touch the request structure.
// But disconnect does not use it either - so we must deref it
// here manually, and that should free it up, and remove the
// temp ref on the connection.
//
// But we do not want the irp to be completed, so we do not call
// AtalkTdiCompleteRequest, and just call deref.
//
AtalkDereferenceTdiRequest("DiscTdiReqPost", Request, RQREF_MAKEREQ);
}
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiDisconnect - Complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiAccept(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
if (NT_SUCCESS(status)) {
status = AtalkConnPostAccept(
(PCONNECTION_FILE)Request->FileObject->FsContext,
Request);
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAccept - Complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiListen(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
PCONNECTION_FILE connection = (PCONNECTION_FILE)Request->FileObject->FsContext;
if (NT_SUCCESS(status)) {
//
// Now verify the associated address object
//
status = AtalkConnVerifyAssocAddress(connection);
if (NT_SUCCESS(status)) {
status = AtalkConnPostListen(
connection,
Request);
//
// Deference the address, connection reference goes during completion
//
AtalkConnDereferenceAssocAddress(connection);
}
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiListen - Complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiSendDatagram(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine sends a datagram.
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForAddress(Request);
if (NT_SUCCESS(status)) {
status = AtalkAddrSendDatagram(
(PADDRESS_FILE)Request->FileObject->FsContext,
Request);
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiSendDatagram - complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiReceiveDatagram(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine receives a datagram.
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForAddress(Request);
if (NT_SUCCESS(status)) {
status = AtalkAddrReceiveDatagram(
(PADDRESS_FILE)Request->FileObject->FsContext,
Request);
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiReceiveDatagram - complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiSend(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine sends the data specified. (used by PAP/ADSP only)
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
if (NT_SUCCESS(status)) {
//
// Go ahead and post the write
//
status = AtalkConnSend(
(PCONNECTION_FILE)Request->FileObject->FsContext,
Request);
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkConnSend - Complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkTdiReceive(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine receives data. (used by PAP/ADSP only)
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = AtalkCheckRefReqForConnection(Request);
if (NT_SUCCESS(status)) {
//
// Go ahead and post the read
//
status = AtalkConnReceive(
(PCONNECTION_FILE)Request->FileObject->FsContext,
Request);
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkConnReceive - Complete %lx\n", status));
return(status);
}
NTSTATUS
AtalkCheckRefReqForConnection(
IN PATALK_TDI_REQUEST Request
)
{
NTSTATUS status = STATUS_SUCCESS;
PCONNECTION_FILE connection;
connection = (PCONNECTION_FILE)Request->FileObject->FsContext;
AtalkVerifyIsConnectionObject(status,connection, Request->FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Remember we need to dereference the object during request completion
//
Request->Owner = connection;
Request->OwnerType = TDI_CONNECTION_FILE;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
if (Request->DeviceContext->DeviceType != connection->OwningDevice) {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCheckRefConn - Providers not the same %lx\n",
connection));
ASSERT(0);
}
}
return(status);
}
NTSTATUS
AtalkCheckRefReqForAddress(
IN PATALK_TDI_REQUEST Request
)
{
NTSTATUS status = STATUS_SUCCESS;
PADDRESS_FILE address;
address = (PADDRESS_FILE)Request->FileObject->FsContext;
AtalkVerifyIsAddressObject(status, address, Request->FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Remember we need to dereference the object during request completion
//
Request->Owner = address;
Request->OwnerType = TDI_TRANSPORT_ADDRESS_FILE;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
if (Request->DeviceContext->DeviceType != address->OwningDevice) {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCheckRefAddr - Providers not the same %lx\n",
address));
ASSERT(0);
}
}
return(status);
}
NTSTATUS
AtalkTdiAction(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine is the dispatch routine for all the TdiAction primitives
for all the providers
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PTDI_ACTION_HEADER actionHeader;
ULONG bufferLength;
ULONG actionCode;
//
// Preliminary checks
// If mdl address is NULL, we return
//
if (Request->Action.MdlAddress == NULL) {
return(STATUS_INVALID_PARAMETER);
}
//
// BUGBUG: MDL Could be fragmented. Check size and make/use a copy if so
//
actionHeader =
(PTDI_ACTION_HEADER)MmGetSystemAddressForMdl(Request->Action.MdlAddress);
AtalkGetMdlChainLength(Request->Action.MdlAddress, &bufferLength);
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAction - Action code %lx BufLen %d SysAddress %lx\n",
actionHeader->ActionCode, bufferLength, actionHeader));
//
// If we atleast do not have the action header, return
//
if (bufferLength < sizeof(TDI_ACTION_HEADER)) {
return(STATUS_INVALID_PARAMETER);
}
//
// If the MATK identifier is not present, we return
//
if (actionHeader->TransportId != MATK) {
return(STATUS_INVALID_DEVICE_REQUEST);
}
//
// Handle the requests based on the action code.
// Use the table to call the appropriate routine
//
actionCode = actionHeader->ActionCode;
if ((actionCode >= MIN_COMMON_ACTIONCODE) &&
(actionCode <= MAX_ALLACTIONCODES)) {
PVOID object;
INT objectType;
INT deviceType;
ULONG opInfo = ActionDispatch[actionCode]._OpInfo;
do {
if (bufferLength < ActionDispatch[actionCode]._MinBufLen) {
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAction - Minbuflen %d Expected %d\n",
bufferLength, ActionDispatch[actionCode]._MinBufLen));
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// 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. Note that
// ANY matches all devices except APPLETALK.
//
if ((ActionDispatch[actionCode]._DeviceType !=
ATALK_DEVICE_ANY) &&
(Request->DeviceContext->DeviceType !=
ActionDispatch[actionCode]._DeviceType)) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
objectType = (INT)Request->FileObject->FsContext2;
object = (PVOID)Request->FileObject->FsContext;
//
// Verify the object - it has to be one of those specified as valid
// in the dispatch table for this action call.
//
do {
//
// Atleast one of the object types should be specified
//
ASSERT(opInfo & (DFLAG_ADDRESS |
DFLAG_CONTROLCHANNEL |
DFLAG_CONNECTION));
status = STATUS_INVALID_HANDLE;
if (opInfo & DFLAG_ADDRESS) {
AtalkVerifyIsAddressObject(status,
((PADDRESS_FILE)object),
(PVOID)objectType);
if (NT_SUCCESS(status)) {
deviceType = ((PADDRESS_FILE)object)->OwningDevice;
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAction - Ver %lx passed as addr\n", object));
break;
}
}
if (opInfo & DFLAG_CONTROLCHANNEL) {
AtalkVerifyIsControlChannelObject(status,
((PCONTROLCHANNEL_FILE)object),
(PVOID)objectType);
if (NT_SUCCESS(status)) {
deviceType = ((PCONTROLCHANNEL_FILE)object)->OwningDevice;
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAction - Ver %lx passed as cc\n", object));
break;
}
}
if (opInfo & DFLAG_CONNECTION ) {
AtalkVerifyIsConnectionObject(status,
((PCONNECTION_FILE)object),
(PVOID)objectType);
if (NT_SUCCESS(status)) {
deviceType = ((PCONNECTION_FILE)object)->OwningDevice;
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAction - Ver %lx passed as conn\n", object));
break;
}
}
break;
} while (FALSE);
if (!NT_SUCCESS(status)) {
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAction - Ver %lx failed! %lx\n", object, status));
break;
}
//
// remember the owner of this request and that we need to dereference
// owner upon completion of this request
//
Request->Owner = object;
Request->OwnerType = objectType;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
Request->ActionCode = actionCode;
//
// Check to see if provider types match
//
if (Request->DeviceContext->DeviceType != deviceType) {
status = STATUS_NO_SUCH_DEVICE;
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAction - Providers not the same %lx\n", object));
ASSERT(0);
break;
}
//
// Queue the request to the object -if it fails, this will
// be because the object is shutting down
//
switch (objectType) {
case TDI_TRANSPORT_ADDRESS_FILE:
//
// Acquire the spinlock and then queue the request in there
// Check state to make sure it is not closing/stopping etc.
// as appropriate
//
ACQUIRE_SPIN_LOCK(&((PADDRESS_FILE)object)->AddressLock);
if (((PADDRESS_FILE)object)->Flags & ADDRESS_FLAGS_CLOSING) {
status = STATUS_INVALID_ADDRESS;
} else {
InsertTailList(&((PADDRESS_FILE)object)->RequestLinkage,
&Request->Linkage);
}
RELEASE_SPIN_LOCK(&((PADDRESS_FILE)object)->AddressLock);
break;
case ATALK_FILE_TYPE_CONTROL:
ACQUIRE_SPIN_LOCK(&((PCONTROLCHANNEL_FILE)object)->ControlChannelLock);
if (((PCONTROLCHANNEL_FILE)object)->Flags &
CONTROLCHANNEL_FLAGS_CLOSING) {
// BUGBUG: Get a control channel related code in ntstatus.h
status = STATUS_UNSUCCESSFUL;
} else {
InsertTailList(&((PCONTROLCHANNEL_FILE)object)->RequestLinkage,
&Request->Linkage);
}
RELEASE_SPIN_LOCK(&((PCONTROLCHANNEL_FILE)object)->ControlChannelLock);
break;
case TDI_CONNECTION_FILE:
ACQUIRE_SPIN_LOCK(&((PCONNECTION_FILE)object)->ConnectionLock);
if (((((PCONNECTION_FILE)object)->Flags & CONNECTION_FLAGS_ACTIVE)
== 0) ||
(((PCONNECTION_FILE)object)->Flags &
(CONNECTION_FLAGS_DEFERREDDISC |
CONNECTION_FLAGS_DISCONNECTING |
CONNECTION_FLAGS_STOPPING |
CONNECTION_FLAGS_CLOSING))) {
status =
((((PCONNECTION_FILE)object)->Flags & CONNECTION_FLAGS_ACTIVE) ?
((PCONNECTION_FILE)object)->DisconnectStatus : \
STATUS_INVALID_CONNECTION);
} else {
InsertTailList(&((PCONNECTION_FILE)object)->RequestLinkage,
&Request->Linkage);
}
RELEASE_SPIN_LOCK(&((PCONNECTION_FILE)object)->ConnectionLock);
break;
default:
KeBugCheck(0);
}
if (!NT_SUCCESS(status)) {
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAction - Queue request failed! %lx\n", status));
break;
}
//
// Create MDLs as indicated
//
{
PMDL newCurrentMdl;
ULONG newByteOffset ;
ULONG trueLength;
USHORT i;
ULONG dFlagMdl = DFLAG_MDL1;
ULONG offset = ActionDispatch[actionCode]._ActionBufSize;
ULONG size = 0;
//
// If DFLAG_MDL1 is set, then we know we have to create the
// first mdl. The size for the first depends on whether DFLAG_MDL2
// is set or not. If set, we have to calculate the size else
// we use all of the buffer excluding the action header for
// the first (and in this case only) mdl.
//
// Similarly for MDL2 and MDL3 with the exception that the size
// of the buffer for MDL3 is all the remaining space in the
// buffer
//
// BUGBUG: 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.
//
status = STATUS_INVALID_PARAMETER;
for (i = 0; i < MAX_REQUESTMDLS; i++) {
if (opInfo & dFlagMdl) {
if (opInfo & (dFlagMdl << 1)) {
size = *(PULONG)((PCHAR)actionHeader +
ActionDispatch[actionCode]._MdlSizeOffset[i]);
} else {
size = bufferLength - offset;
}
} else {
status = STATUS_SUCCESS;
break;
}
ASSERT((size >= 0) && (offset+size <= bufferLength));
if ((size < 0) || ((offset+size) > bufferLength)) {
break;
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiAction - Size of %d mdl %lx\n", i+1, size));
status = BuildMdlChainFromMdlChain (
Request->Action.MdlAddress, // MasterMdl
offset, // ByteOffset,
size, // SubsetMdlSize,
&Request->MdlChain[i], // subsetMdl,
&newCurrentMdl,
&newByteOffset,
&trueLength);
ASSERT(trueLength == size);
if (NT_SUCCESS(status)) {
// Set the mdl size
Request->MdlSize[i] = trueLength;
} else {
ASSERT(Request->MdlChain[i] == NULL);
break;
}
dFlagMdl <<= 1;
}
}
if (!NT_SUCCESS(status)) {
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAction - Make MDLs failed %lx\n", status));
break;
}
//
// Set the completion routine in request block and call the dispatch
// routine
//
Request->CompletionRoutine = ActionDispatch[actionCode]._Completion;
status = (ActionDispatch[actionCode]._Dispatch)(Request);
//
// if request was not successfully queued OR if it was successfully
// completed (synchronous), call completion routine here and return
// STATUS_PENDING
//
if (status != STATUS_PENDING) {
AtalkTdiActionComplete(Request, status);
status = STATUS_PENDING;
break;
}
break;
} while (FALSE);
} else {
DBGPRINT(ATALK_DEBUG_ACTION, DEBUG_LEVEL_ERROR,
("ERROR: AtalkTdiAction - Invalid action code %d\n", actionCode));
status = STATUS_INVALID_PARAMETER;
}
return(status);
}
VOID
AtalkTdiActionComplete(
IN PATALK_TDI_REQUEST Request,
IN NTSTATUS CompletionStatus
)
/*++
Routine Description:
This is the generic completion routine for all tdi action primitives.
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
NONE
--*/
{
PVOID object;
object = (PVOID)Request->Owner;
switch ((INT)Request->OwnerType) {
case TDI_TRANSPORT_ADDRESS_FILE :
//
// Acquire the spinlock and then dequeue the request
//
ACQUIRE_SPIN_LOCK(&((PADDRESS_FILE)object)->AddressLock);
RemoveEntryList(&Request->Linkage);
InitializeListHead(&Request->Linkage);
RELEASE_SPIN_LOCK(&((PADDRESS_FILE)object)->AddressLock);
break;
case ATALK_FILE_TYPE_CONTROL :
ACQUIRE_SPIN_LOCK(&((PCONTROLCHANNEL_FILE)object)->ControlChannelLock);
RemoveEntryList(&Request->Linkage);
InitializeListHead(&Request->Linkage);
RELEASE_SPIN_LOCK(&((PCONTROLCHANNEL_FILE)object)->ControlChannelLock);
break;
case TDI_CONNECTION_FILE:
ACQUIRE_SPIN_LOCK(&((PCONNECTION_FILE)object)->ConnectionLock);
RemoveEntryList(&Request->Linkage);
InitializeListHead(&Request->Linkage);
RELEASE_SPIN_LOCK(&((PCONNECTION_FILE)object)->ConnectionLock);
break;
default:
KeBugCheck(0);
}
//
// Complete the request
//
AtalkCompleteTdiRequest(Request, CompletionStatus);
return;
}
//
// BUGBUG: Move this elsewhere
//
#define MIN_TDIADDRINFOSIZE 0x10
NTSTATUS
AtalkTdiQueryInformation(
IN PATALK_TDI_REQUEST Request
)
/*++
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
The connection information for the connection object passed in.
TDI_QUERY_PROVIDER_STATISTICS
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:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status = STATUS_BUFFER_OVERFLOW;
ULONG mdlBufferSize;
PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
PTDI_PROVIDER_STATISTICS providerStatistics;
PTDI_CONNECTION_INFO connectionInfo;
PCONNECTION_FILE connection;
PADDRESS_FILE address;
query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)Request->Parameters;
AtalkGetMdlChainLength (Request->Query.MdlAddress, &mdlBufferSize);
//
// Set number of bytes written to 0
//
Request->IoStatus->Information = 0;
switch (query->QueryType) {
case TDI_QUERY_ADDRESS_INFO:
//
// Address info is queried on an address
// BUGBUG: This structure is going to change - do final changes then
//
if (mdlBufferSize < MIN_TDIADDRINFOSIZE) {
break;
}
address = (PADDRESS_FILE)Request->FileObject->FsContext;
AtalkVerifyIsAddressObject(status,address, Request->FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Remember we need to dereference the object during request completion
//
Request->Owner = address;
Request->OwnerType = TDI_TRANSPORT_ADDRESS_FILE;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
status = STATUS_NO_SUCH_DEVICE;
if (Request->DeviceContext->DeviceType == address->OwningDevice) {
CHAR addressBuffer[MIN_TDIADDRINFOSIZE];
PTDI_ADDRESS_INFO addressInfo = (PTDI_ADDRESS_INFO)addressBuffer;
//
// Go ahead and obtain the address
//
status = AtalkAddrQueryAddress(
address,
addressInfo);
if (NT_SUCCESS(status)) {
status = TdiCopyBufferToMdl (
(PVOID)addressInfo,
0L,
MIN_TDIADDRINFOSIZE,
Request->Query.MdlAddress,
0,
&(Request->IoStatus->Information));
}
}
} else {
connection = (PCONNECTION_FILE)Request->FileObject->FsContext;
AtalkVerifyIsConnectionObject(status, connection,
Request->FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Remember we need to dereference the object during request
// completion
//
Request->Owner = connection;
Request->OwnerType = TDI_CONNECTION_FILE;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
status = STATUS_NO_SUCH_DEVICE;
if (Request->DeviceContext->DeviceType == connection->OwningDevice) {
CHAR addressBuffer[MIN_TDIADDRINFOSIZE];
PTDI_ADDRESS_INFO addressInfo =
(PTDI_ADDRESS_INFO)addressBuffer;
//
// Go ahead and obtain the address of the connections associated
// address
//
address = connection->AssociatedAddress;
status = AtalkVerifyAddressObject(address);
if (NT_SUCCESS(status)) {
status = AtalkAddrQueryAddress(
connection->AssociatedAddress,
addressInfo);
if (NT_SUCCESS(status)) {
status = TdiCopyBufferToMdl (
(PVOID)addressInfo,
0L,
MIN_TDIADDRINFOSIZE,
Request->Query.MdlAddress,
0,
&(Request->IoStatus->Information));
}
AtalkDereferenceAddress("verQuery", address, AREF_VERIFY,
SECONDARY_REFSET);
}
}
}
}
break;
case TDI_QUERY_CONNECTION_INFO:
//
// Connection info is queried on a connection,
//
if (mdlBufferSize < sizeof(TDI_CONNECTION_INFO)) {
break;
}
connection = (PCONNECTION_FILE)Request->FileObject->FsContext;
AtalkVerifyIsConnectionObject(status,connection, Request->FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Remember we need to dereference the object during request completion
//
Request->Owner = connection;
Request->OwnerType = TDI_CONNECTION_FILE;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
//
// Allocate the memory for the connectionInfo
//
connectionInfo =
(PTDI_CONNECTION_INFO)AtalkAllocNonPagedMemory(sizeof(TDI_CONNECTION_INFO));
status = STATUS_INSUFFICIENT_RESOURCES;
if (connectionInfo != NULL) {
status = STATUS_NO_SUCH_DEVICE;
if (Request->DeviceContext->DeviceType == connection->OwningDevice) {
//
// Go ahead and calculate the statistics
//
status = AtalkConnQueryStatistics(
connection,
connectionInfo);
if (NT_SUCCESS(status)) {
status = TdiCopyBufferToMdl (
(PVOID)connectionInfo,
0L,
sizeof(TDI_CONNECTION_INFO),
Request->Query.MdlAddress,
0,
&(Request->IoStatus->Information));
}
}
AtalkFreeNonPagedMemory (connectionInfo);
}
}
break;
case TDI_QUERY_PROVIDER_INFO:
if (mdlBufferSize < sizeof(TDI_PROVIDER_INFO)) {
break;
}
status = TdiCopyBufferToMdl (
&(Request->DeviceContext->ProviderInfo),
0,
sizeof (TDI_PROVIDER_INFO),
Request->Query.MdlAddress,
0,
&Request->IoStatus->Information);
break;
case TDI_QUERY_PROVIDER_STATISTICS:
if (mdlBufferSize < sizeof(TDI_PROVIDER_STATISTICS)) {
break;
}
status = TdiCopyBufferToMdl (
(PVOID)&(Request->DeviceContext->ProviderStatistics),
0L,
sizeof(TDI_PROVIDER_STATISTICS),
Request->Query.MdlAddress,
0,
&(Request->IoStatus->Information));
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return status;
} /* AtalkTdiQueryInformation */
NTSTATUS
AtalkTdiSetInformation(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status;
status = STATUS_NOT_IMPLEMENTED;
return(status);
}
NTSTATUS
AtalkTdiSetEventHandler(
IN PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine
Arguments:
Request- The request structure we use for all tdi requests
Return Value:
STATUS_SUCCESS if successfully completed
STATUS_PENDING if successfully started
Error otherwise.
--*/
{
NTSTATUS status;
PADDRESS_FILE address;
address = (PADDRESS_FILE)Request->FileObject->FsContext;
AtalkVerifyIsAddressObject(status,address, Request->FileObject->FsContext2);
if (NT_SUCCESS(status)) {
//
// Remember we need to dereference the object during request completion
//
Request->Owner = address;
Request->OwnerType = TDI_TRANSPORT_ADDRESS_FILE;
Request->Flags |= REQUEST_FLAGS_DEREFOWNER;
//
// Verify that the provider names are all the same
//
if ((address->OwningDevice == Request->DeviceContext->DeviceType)) {
status = AtalkAddrSetEventHandler(
address,
Request);
} else {
status = STATUS_INVALID_DEVICE_REQUEST;
}
}
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkTdiSetEventHandler - complete %lx\n", status));
return(status);
}