|
|
/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
smbtdi.h
Abstract:
Wrappers for TDI
Author:
Jiandong Ruan
Revision History:
--*/
#ifndef __SMBTDI_H__
#define __SMBTDI_H__
#ifndef TDI_MINIMUM_INDICATE
#define TDI_MINIMUM_INDICATE 128
#endif
#define INVALID_INTERFACE_INDEX (0xffff)
struct _SMB_ASYNC_CONTEXT; typedef struct _SMB_ASYNC_CONTEXT SMB_ASYNC_CONTEXT, *PSMB_ASYNC_CONTEXT;
typedef void (*PSMB_TDI_COMPLETION) ( IN PSMB_ASYNC_CONTEXT AsyncContext ); struct _SMB_ASYNC_CONTEXT { LIST_ENTRY Linkage; PVOID AsyncInternalContext; // Internally used by the asychn routine.
KTIMER Timer; KDPC Dpc;
PSMB_TDI_COMPLETION Completion; PVOID ClientContext; DWORD Timeout;
NTSTATUS status; };
#define SMB_TDI_TIMEOUT_INFINITE (0xffffffffU)
void __inline SmbInitAsyncContext( IN OUT PSMB_ASYNC_CONTEXT Context, IN PSMB_TDI_COMPLETION ClientCompletion, IN PVOID ClientContext, IN DWORD Timeout ) { PAGED_CODE();
InitializeListHead(&Context->Linkage);
Context->AsyncInternalContext = NULL;
Context->Completion = ClientCompletion; Context->ClientContext = ClientContext; Context->Timeout = Timeout; Context->status = STATUS_PENDING; }
void __inline SmbAsyncStartTimer( IN OUT PSMB_ASYNC_CONTEXT Context, IN PKDEFERRED_ROUTINE TimeoutCompletion ) { LARGE_INTEGER DueTime;
PAGED_CODE();
if (Context->Timeout != SMB_TDI_TIMEOUT_INFINITE) { KeInitializeTimer(&Context->Timer); KeInitializeDpc(&Context->Dpc, TimeoutCompletion, Context); DueTime.QuadPart = -Int32x32To64(Context->Timeout, 10000);
KeSetTimer(&Context->Timer, DueTime, &Context->Dpc); } }
void __inline SmbAsyncStopTimer( IN OUT PSMB_ASYNC_CONTEXT Context ) { if (Context->Timeout != SMB_TDI_TIMEOUT_INFINITE) { KeCancelTimer(&Context->Timer); } }
void __inline SmbAsyncCompleteRequest( IN OUT PSMB_ASYNC_CONTEXT Context ) { SmbAsyncStopTimer(Context); Context->Completion((PSMB_ASYNC_CONTEXT)Context); }
/*
* TCP Address object */ typedef struct { PDEVICE_OBJECT DeviceObject; HANDLE AddressHandle; PFILE_OBJECT AddressObject; } SMB_TCP_ADDRESS, *PSMB_TCP_ADDRESS;
VOID __inline SmbInitTcpAddress( IN OUT PSMB_TCP_ADDRESS Context ) { Context->DeviceObject = NULL; Context->AddressHandle = NULL; Context->AddressObject = NULL; }
BOOL __inline ValidTcpAddress( IN OUT PSMB_TCP_ADDRESS Context ) { return (Context->DeviceObject && Context->AddressHandle && Context->AddressObject); }
typedef struct { HANDLE ConnectHandle; PFILE_OBJECT ConnectObject; PVOID UpperConnect;
// for debugging purpose.
// We save a copy here so that we
// can find out the upper connection
// even when UpperConnect is null-ed
// out.
PVOID pLastUprCnt; } SMB_TCP_CONNECT, *PSMB_TCP_CONNECT;
VOID __inline SmbInitTcpConnect( IN OUT PSMB_TCP_CONNECT Context ) { Context->ConnectHandle = NULL; Context->ConnectObject = NULL; Context->UpperConnect = NULL; }
BOOL __inline ValidTcpConnect( IN OUT PSMB_TCP_CONNECT Context ) { return (Context->ConnectHandle && Context->ConnectObject); }
//
// Placeholder for IP FastQuery routine to determine InterfaceContext + metric for dest addr
//
typedef NTSTATUS (*PIP4FASTQUERY)( IN IPAddr Address, OUT PULONG pIndex, OUT PULONG pMetric ); typedef NTSTATUS (*PIP6FASTQUERY)( IN PSMB_IP6_ADDRESS Address, OUT PULONG pIndex, OUT PULONG pMetric );
//
// Placeholder for TCP Send routine if Fast Send is possible
//
typedef NTSTATUS (*PTCPSEND_DISPATCH) ( IN PIRP Irp, IN PIO_STACK_LOCATION irpsp );
//
// SMB is bound to either TCP4 or TCP6, or both.
// We have a record for each binding.
//
// We use this data structure to cache our connection object with TCP
// Opening new TCP connection can only be done at PASSIVE level. However,
// due to the following reasons, we need a TCP connection object at
// DISPATCH level,
// 1. For outbound request, we don't know whether we're going to use TCP4
// or TCP6 until the name resoltuion is done. Our DNS name resolution
// completion routine could be called at DISPATCH level.
// 2. For inbound requests, we don't know whether we're going to use TCP4
// or TCP6 until our TdiConnectHandler is called. Again, it is called
// at DISPATCH level.
// To allow SMB get an TCP connection whenever it needs it, we use the following
// data structure to cache the connection object.
//
// The cache algorithm works as follow:
// Parameters: L, M, L < M
// 1. During initialization, we create M TCP connection object;
// 2. Whenever the number of connection objects goes below L, we start a
// worker thread to bring it up to M.
//
typedef struct _SMB_TCP_INFO { KSPIN_LOCK Lock;
//
// The TDI event context. We need this context to set TDI event handler
//
PVOID TdiEventContext;
SMB_IP_ADDRESS IpAddress; // The local Ip address (in Network Order)
USHORT Port; // The listening port (in network order)
SMB_TCP_ADDRESS InboundAddressObject; // The TCP address object we're lisening on
LIST_ENTRY InboundPool; LONG InboundNumber; // Number of entries in InboundPool
LONG InboundLow, InboundMid, InboundHigh;
LIST_ENTRY DelayedDestroyList;
//
// Control channel: used to send IOCTLs to TCP
//
USHORT TcpStackSize; PFILE_OBJECT TCPControlFileObject; PDEVICE_OBJECT TCPControlDeviceObject; PFILE_OBJECT IPControlFileObject; PDEVICE_OBJECT IPControlDeviceObject;
//
// FastSend and FastQuery routine
//
PTCPSEND_DISPATCH FastSend; PVOID FastQuery;
//
// We use the loopback interface index to determine if an IP is local or not
// 1. Query the outgoing interface from TCP
// 2. If the index of outgoing interface is loopback, then the IP is a local IP.
//
ULONG LoopbackInterfaceIndex; } SMB_TCP_INFO, *PSMB_TCP_INFO;
//
// Used to store the connection information with TCP
//
typedef struct { LIST_ENTRY Linkage;
PSMB_TCP_INFO CacheOwner;
//
// The IRP which is used to do the disconnect
// This field is put here only for saving debugging time
// When we see disconnect problem, IRP can tell us
// where we are. (We did see the request pending in TCP forever.)
//
PIRP DisconnectIrp;
SMB_TCP_ADDRESS Address; SMB_TCP_CONNECT Connect; } SMB_TCP_CONTEXT, *PSMB_TCP_CONTEXT;
NTSTATUS SmbInitTCP4( PSMB_TCP_INFO TcpInfo, USHORT Port, PVOID TdiEventContext );
NTSTATUS SmbInitTCP6( PSMB_TCP_INFO TcpInfo, USHORT Port, PVOID TdiEventContext );
NTSTATUS SmbShutdownTCP( PSMB_TCP_INFO TcpInfo );
VOID SmbReadTCPConf( IN HANDLE hKey, PSMB_TCP_INFO TcpInfo );
NTSTATUS SmbSynchConnCache( PSMB_TCP_INFO TcpInfo, BOOL Cleanup );
PSMB_TCP_CONTEXT SmbAllocateOutbound( PSMB_TCP_INFO TcpInfo );
VOID SmbFreeOutbound( PSMB_TCP_CONTEXT TcpCtx );
PSMB_TCP_CONTEXT SmbAllocateInbound( PSMB_TCP_INFO TcpInfo );
VOID SmbFreeInbound( PSMB_TCP_CONTEXT TcpCtx );
VOID SmbFreeTcpContext( PSMB_TCP_CONTEXT TcpCtx );
VOID SmbDelayedDestroyTcpContext( PSMB_TCP_CONTEXT TcpCtx );
typedef struct _SMB_DEVICE SMB_DEVICE, *PSMB_DEVICE; NTSTATUS SmbWakeupWorkerThread( IN PSMB_DEVICE DeviceObject );
VOID __inline SmbInitTcpContext( IN OUT PSMB_TCP_CONTEXT Context ) { InitializeListHead(&Context->Linkage); Context->DisconnectIrp = NULL; SmbInitTcpAddress(&Context->Address); SmbInitTcpConnect(&Context->Connect); }
NTSTATUS SmbOpenTcpAddress( IN PSMB_IP_ADDRESS addr, IN USHORT port, IN OUT PSMB_TCP_ADDRESS context );
NTSTATUS SmbOpenUdpAddress( IN PSMB_IP_ADDRESS addr, IN USHORT port, IN OUT PSMB_TCP_ADDRESS context );
NTSTATUS SmbCloseAddress( IN OUT PSMB_TCP_ADDRESS context );
NTSTATUS SmbOpenTcpConnection( IN PSMB_TCP_ADDRESS Address, IN OUT PSMB_TCP_CONNECT Connect, IN PVOID ConnectionContext );
NTSTATUS SmbCloseTcpConnection( IN OUT PSMB_TCP_CONNECT Connect );
NTSTATUS TdiSetEventHandler( PFILE_OBJECT FileObject, ULONG EventType, PVOID EventHandler, PVOID Context );
typedef struct { SMB_ASYNC_CONTEXT; ULONG Id; // TransactionId
PTDI_ADDRESS_NETBIOS_UNICODE_EX pUnicodeAddress; UNICODE_STRING FQDN;
LONG ipaddr_num; SMB_IP_ADDRESS ipaddr[SMB_MAX_IPADDRS_PER_HOST]; } SMB_GETHOST_CONTEXT, *PSMB_GETHOST_CONTEXT;
BOOL SmbLookupHost( WCHAR *host, PSMB_IP_ADDRESS ipaddr );
void SmbAsyncGetHostByName( IN PUNICODE_STRING Name, IN PSMB_GETHOST_CONTEXT Context );
typedef struct { SMB_ASYNC_CONTEXT;
// Local end point
SMB_TCP_CONNECT TcpConnect;
//
// GetHostByName returns multiple IP address.
// We try to connect to each of them until
// we succeed in making a connection
//
// the result of GetHostByName
PSMB_GETHOST_CONTEXT pSmbGetHostContext; // the IP address currently being tried
USHORT usCurrentIP;
PIO_WORKITEM pIoWorkItem;
} SMB_CONNECT_CONTEXT, *PSMB_CONNECT_CONTEXT; typedef struct _SMB_CONNECT SMB_CONNECT, *PSMB_CONNECT; typedef struct _SMB_DEVICE SMB_DEVICE, *PSMB_DEVICE;
typedef NTSTATUS (*PRECEIVE_HANDLER) ( IN PSMB_DEVICE DeviceObject, IN PSMB_CONNECT ConnectObject, IN ULONG ReceiveFlags, IN LONG BytesIndicated, IN LONG BytesAvailable, OUT LONG *BytesTaken, IN PVOID Tsdu, OUT PIRP *Irp );
#ifndef __SMB_KDEXT__
void SmbAsyncConnect( IN PSMB_IP_ADDRESS ipaddr, IN USHORT port, IN PSMB_CONNECT_CONTEXT Context );
NTSTATUS SmbTcpDisconnect( PSMB_TCP_CONTEXT TcpContext, LONG TimeoutMilliseconds, ULONG Flags );
NTSTATUS SmbAsynchTcpDisconnect( PSMB_TCP_CONTEXT TcpContext, ULONG Flags );
NTSTATUS SmbSetTcpEventHandlers( PFILE_OBJECT AddressObject, PVOID Context );
NTSTATUS SubmitSynchTdiRequest ( IN PFILE_OBJECT FileObject, IN PIRP Irp );
NTSTATUS SmbSendIoctl( PFILE_OBJECT FileObject, ULONG Ioctl, PVOID InBuf, ULONG InBufSize, PVOID OutBuf, ULONG *OutBufSize );
NTSTATUS SmbSetTcpInfo( IN PFILE_OBJECT FileObject, IN ULONG Entity, IN ULONG Class, IN ULONG ToiId, IN ULONG ToiType, IN ULONG InfoBufferValue );
#define ATTACH_FSP(Attached) \
do { \ if (PsGetCurrentProcess() != SmbCfg.FspProcess) { \ Attached = TRUE; \ KeAttachProcess((PRKPROCESS)SmbCfg.FspProcess); \ } else { \ Attached = FALSE; \ } \ } while(0)
#define DETACH_FSP(Attached) \
do { \ if (Attached) { \ KeDetachProcess(); \ } \ } while(0)
#endif // __SMB_KDEXT__
#endif // __SMBTDI_H__
|