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.
727 lines
18 KiB
727 lines
18 KiB
#define SRVDBG 1
|
|
#define SRVKD 1
|
|
#define NDIS40_MINIPORT 1
|
|
#define NDIS_MINIPORT_DRIVER 1
|
|
#define NT
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntverp.h>
|
|
#include <windef.h>
|
|
#include <winbase.h>
|
|
#include <ntosp.h>
|
|
#include <wdbgexts.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <raspptp.h>
|
|
#include <bpool.h>
|
|
|
|
typedef struct CTDI_DATA *PCTDI_DATA;
|
|
|
|
typedef struct CTDI_DATA {
|
|
LIST_ENTRY ListEntry;
|
|
ULONG Signature;
|
|
ULONG Type;
|
|
REFERENCE_COUNT Reference;
|
|
HANDLE hFile;
|
|
PFILE_OBJECT pFileObject;
|
|
NDIS_SPIN_LOCK Lock;
|
|
BOOLEAN Closed;
|
|
|
|
CTDI_EVENT_CONNECT_QUERY ConnectQueryCallback;
|
|
CTDI_EVENT_CONNECT_COMPLETE ConnectCompleteCallback;
|
|
CTDI_EVENT_DISCONNECT DisconnectCallback;
|
|
CTDI_EVENT_RECEIVE RecvCallback;
|
|
PVOID RecvContext;
|
|
CTDI_EVENT_RECEIVE_DATAGRAM RecvDatagramCallback;
|
|
CTDI_EVENT_SEND_COMPLETE SendCompleteCallback;
|
|
CTDI_EVENT_QUERY_COMPLETE QueryCompleteCallback;
|
|
CTDI_EVENT_SET_COMPLETE SetCompleteCallback;
|
|
|
|
union {
|
|
struct {
|
|
PVOID Context;
|
|
LIST_ENTRY ConnectList;
|
|
ULONG NumConnection;
|
|
} Listen;
|
|
struct {
|
|
PVOID Context;
|
|
PCTDI_DATA LocalEndpoint;
|
|
PVOID ConnectInfo;
|
|
TA_IP_ADDRESS RemoteAddress;
|
|
LIST_ENTRY ListEntry;
|
|
ULONG DisconnectCount;
|
|
union {
|
|
BOOLEAN Disconnect;
|
|
ULONG_PTR Padding1;
|
|
};
|
|
union {
|
|
BOOLEAN Abort;
|
|
ULONG_PTR Padding2;
|
|
};
|
|
} Connection;
|
|
struct {
|
|
BUFFERPOOL RxPool;
|
|
} Datagram;
|
|
};
|
|
} CTDI_DATA, *PCTDI_DATA;
|
|
|
|
#define CTDI_UNKNOWN 'NKNU'
|
|
#define CTDI_ENDPOINT 'PDNE'
|
|
#define CTDI_DATAGRAM 'MRGD'
|
|
#define CTDI_LISTEN 'TSIL'
|
|
#define CTDI_CONNECTION 'NNOC'
|
|
|
|
|
|
WINDBG_EXTENSION_APIS ExtensionApis;
|
|
EXT_API_VERSION ApiVersion = { 5, 0, EXT_API_VERSION_NUMBER, 0 };
|
|
|
|
#define ERRPRT dprintf
|
|
|
|
#define NL 1
|
|
#define NONL 0
|
|
|
|
USHORT SavedMajorVersion;
|
|
USHORT SavedMinorVersion;
|
|
BOOL ChkTarget; // is debuggee a CHK build?
|
|
|
|
|
|
typedef struct
|
|
{
|
|
char Name[16];
|
|
int Val;
|
|
} DBG_LEVEL;
|
|
|
|
|
|
|
|
/*
|
|
* Print out an optional message, an ANSI_STRING, and maybe a new-line
|
|
*/
|
|
BOOL
|
|
PrintStringA( IN LPSTR msg OPTIONAL, IN PANSI_STRING pStr, IN BOOL nl )
|
|
{
|
|
PCHAR StringData;
|
|
ULONG BytesRead;
|
|
|
|
if( msg )
|
|
dprintf( msg );
|
|
|
|
if( pStr->Length == 0 ) {
|
|
if( nl )
|
|
dprintf( "\n" );
|
|
return TRUE;
|
|
}
|
|
|
|
StringData = (PCHAR)LocalAlloc( LPTR, pStr->Length + 1 );
|
|
|
|
if( StringData == NULL ) {
|
|
ERRPRT( "Out of memory!\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
ReadMemory((ULONG)((ULONG_PTR) pStr->Buffer),
|
|
StringData,
|
|
pStr->Length,
|
|
&BytesRead );
|
|
|
|
if ( BytesRead ) {
|
|
StringData[ pStr->Length ] = '\0';
|
|
dprintf("%s%s", StringData, nl ? "\n" : "" );
|
|
}
|
|
|
|
LocalFree((HLOCAL)StringData);
|
|
|
|
return BytesRead;
|
|
}
|
|
|
|
/*
|
|
* Get 'size' bytes from the debuggee program at 'dwAddress' and place it
|
|
* in our address space at 'ptr'. Use 'type' in an error printout if necessary
|
|
*/
|
|
BOOL
|
|
GetData( IN LPVOID ptr, IN DWORD_PTR dwAddress, IN ULONG size, IN PCSTR type )
|
|
{
|
|
BOOL b;
|
|
ULONG BytesRead;
|
|
ULONG count = size;
|
|
|
|
while( size > 0 ) {
|
|
|
|
if (count >= 3000)
|
|
count = 3000;
|
|
|
|
b = ReadMemory((ULONG) dwAddress, ptr, count, &BytesRead );
|
|
|
|
if (!b || BytesRead != count ) {
|
|
ERRPRT( "Unable to read %u bytes at %X, for %s\n", size, dwAddress, type );
|
|
return FALSE;
|
|
}
|
|
|
|
dwAddress += count;
|
|
size -= count;
|
|
ptr = (LPVOID)((ULONG_PTR)ptr + count);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Follow a LIST_ENTRY list beginning with a head at dwListHeadAddr in the debugee's
|
|
* address space. For each element in the list, print out the pointer value at 'offset'
|
|
*/
|
|
BOOL
|
|
PrintListEntryList( IN DWORD dwListHeadAddr, IN LONG offset )
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
ULONG i=0;
|
|
BOOL retval = TRUE;
|
|
ULONG count = 20;
|
|
|
|
if( !GetData( &ListEntry, dwListHeadAddr, sizeof( ListEntry ), "LIST_ENTRY" ) )
|
|
return FALSE;
|
|
|
|
while( count-- ) {
|
|
|
|
if( (DWORD_PTR)ListEntry.Flink == dwListHeadAddr || (DWORD_PTR)ListEntry.Flink == 0 )
|
|
break;
|
|
|
|
if( !GetData( &ListEntry, (DWORD_PTR)ListEntry.Flink, (ULONG)sizeof( ListEntry ), "ListEntry" ) ) {
|
|
retval = FALSE;
|
|
break;
|
|
}
|
|
|
|
dprintf( "%16X%s", (DWORD_PTR)ListEntry.Flink + offset, (i && !(i&3)) ? "\n" : "" );
|
|
i++;
|
|
}
|
|
|
|
|
|
if( count == 0 && (DWORD_PTR)ListEntry.Flink != dwListHeadAddr && ListEntry.Flink ) {
|
|
dprintf( "\nTruncated list dump\n" );
|
|
|
|
} else if( ! ( i && !(i&3) ) ) {
|
|
dprintf( "\n" );
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Print out a single HEX character
|
|
*/
|
|
VOID
|
|
PrintHexChar( IN UCHAR c )
|
|
{
|
|
dprintf( "%c%c", "0123456789abcdef"[ (c>>4)&0xf ], "0123456789abcdef"[ c&0xf ] );
|
|
}
|
|
|
|
/*
|
|
* Print out 'buf' of 'cbuf' bytes as HEX characters
|
|
*/
|
|
VOID
|
|
PrintHexBuf( IN PUCHAR buf, IN ULONG cbuf )
|
|
{
|
|
while( cbuf-- ) {
|
|
PrintHexChar( *buf++ );
|
|
dprintf( " " );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Fetch the null terminated UNICODE string at dwAddress into buf
|
|
*/
|
|
BOOL
|
|
GetString( IN DWORD_PTR dwAddress, IN LPSTR buf, IN ULONG MaxChars )
|
|
{
|
|
do {
|
|
if( !GetData( buf, dwAddress, sizeof( *buf ), "Character" ) )
|
|
return FALSE;
|
|
|
|
dwAddress += sizeof( *buf );
|
|
|
|
} while( --MaxChars && *buf++ != '\0' );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
char *mystrtok ( char *string, char * control )
|
|
{
|
|
static unsigned char *str;
|
|
char *p, *s;
|
|
|
|
if( string )
|
|
str = string;
|
|
|
|
if( str == NULL || *str == '\0' )
|
|
return NULL;
|
|
|
|
//
|
|
// Skip leading delimiters...
|
|
//
|
|
for( ; *str; str++ ) {
|
|
for( s=control; *s; s++ ) {
|
|
if( *str == *s )
|
|
break;
|
|
}
|
|
if( *s == '\0' )
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Was it was all delimiters?
|
|
//
|
|
if( *str == '\0' ) {
|
|
str = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// We've got a string, terminate it at first delimeter
|
|
//
|
|
for( p = str+1; *p; p++ ) {
|
|
for( s = control; *s; s++ ) {
|
|
if( *p == *s ) {
|
|
s = str;
|
|
*p = '\0';
|
|
str = p+1;
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've got a string that ends with the NULL
|
|
//
|
|
s = str;
|
|
str = NULL;
|
|
return s;
|
|
}
|
|
|
|
DECLARE_API( help )
|
|
{
|
|
int i;
|
|
|
|
dprintf("PPTP extenstions:\n");
|
|
|
|
dprintf(" version\n");
|
|
dprintf(" ctdi dump tdi handles\n");
|
|
dprintf(" calls [start [end]] dump call handles\n");
|
|
dprintf(" ctls dump ctl handles\n");
|
|
dprintf(" dbgmsgs dump debug log\n");
|
|
dprintf(" mem dump allocations\n");
|
|
}
|
|
|
|
DECLARE_API( dbgmsgs )
|
|
{
|
|
DWORD p;
|
|
DWORD Last, First;
|
|
char DbgMsg[MAX_MSG_LEN];
|
|
ULONG Read;
|
|
char *DbgMsgs;
|
|
|
|
if (!GetData(&Last,
|
|
GetExpression("raspptp!Last"),
|
|
sizeof(Last), "DWORD"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
|
|
if (!GetData(&First,
|
|
GetExpression("raspptp!First"),
|
|
sizeof(Last), "DWORD"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
DbgMsgs = (char *) GetExpression("raspptp!dbgmsgs");
|
|
|
|
dprintf("\n\n");
|
|
|
|
while (First != Last)
|
|
{
|
|
if (!GetString((DWORD_PTR) (DbgMsgs + First * MAX_MSG_LEN),
|
|
DbgMsg, MAX_MSG_LEN))
|
|
break;
|
|
/*
|
|
ReadMemory((ULONG) (DbgMsgs + First * MAX_MSG_LEN),
|
|
DbgMsg, MAX_MSG_LEN, &Read); */
|
|
dprintf("%s", DbgMsg);
|
|
First++;
|
|
if (First == DBG_MSG_CNT)
|
|
First = 0;
|
|
}
|
|
}
|
|
|
|
DECLARE_API( ctdi )
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
PLIST_ENTRY ListHead;
|
|
ULONG Count = 20;
|
|
char argbuf[ MAX_PATH ];
|
|
|
|
ListHead = (PLIST_ENTRY)GetExpression("raspptp!CtdiList");
|
|
|
|
if (!GetData(&ListEntry,
|
|
(ULONG_PTR)ListHead,
|
|
sizeof(LIST_ENTRY),
|
|
"LIST_ENTRY"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
while (Count-- && ListHead!=ListEntry.Flink)
|
|
{
|
|
CTDI_DATA Ctdi;
|
|
UCHAR TypeStr[sizeof(ULONG)+1];
|
|
if (!GetData(&Ctdi,
|
|
(ULONG_PTR)ListEntry.Flink,
|
|
sizeof(CTDI_DATA),
|
|
"CTDI_DATA"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
memcpy(TypeStr, &Ctdi.Type, sizeof(ULONG));
|
|
TypeStr[sizeof(ULONG)] = 0;
|
|
|
|
dprintf("CTDI:%08x Sig:%08x Type:%s Refs:%d Handle:%08x FileObj:%08x Closed:%d\n",
|
|
ListEntry.Flink, Ctdi.Signature, TypeStr, Ctdi.Reference.Count, Ctdi.hFile, Ctdi.pFileObject, Ctdi.Closed);
|
|
switch (Ctdi.Type)
|
|
{
|
|
case CTDI_CONNECTION:
|
|
dprintf(" Context:%08x Endpoint:%08x Disconnect/Abort:%x/%x\n",
|
|
Ctdi.Connection.Context, Ctdi.Connection.LocalEndpoint,
|
|
Ctdi.Connection.Disconnect, Ctdi.Connection.Abort);
|
|
break;
|
|
case CTDI_LISTEN:
|
|
dprintf(" Context:%08x NumConn:%d\n",
|
|
Ctdi.Listen.Context, Ctdi.Listen.NumConnection);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ListEntry = Ctdi.ListEntry;
|
|
}
|
|
}
|
|
|
|
typedef struct MEM_HDR {
|
|
LIST_ENTRY ListEntry;
|
|
ULONG Size;
|
|
CHAR File[12];
|
|
ULONG Line;
|
|
} MEM_HDR;
|
|
|
|
DECLARE_API( mem )
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
PLIST_ENTRY ListHead;
|
|
ULONG TotalMem = 0;
|
|
char argbuf[ MAX_PATH ];
|
|
|
|
ListHead = (PLIST_ENTRY)GetExpression("raspptp!leAlloc");
|
|
|
|
if (!GetData(&ListEntry,
|
|
(ULONG_PTR)ListHead,
|
|
sizeof(LIST_ENTRY),
|
|
"LIST_ENTRY"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
while (ListHead!=ListEntry.Flink)
|
|
{
|
|
MEM_HDR Mem;
|
|
UCHAR TypeStr[sizeof(ULONG)+1];
|
|
if (!GetData(&Mem,
|
|
(ULONG_PTR)ListEntry.Flink,
|
|
sizeof(MEM_HDR),
|
|
"MEM_HDR"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
dprintf("MEM:%08x Len:%5d File:%-15s Line:%d\n",
|
|
ListEntry.Flink, Mem.Size, Mem.File, Mem.Line);
|
|
TotalMem += Mem.Size;
|
|
ListEntry = Mem.ListEntry;
|
|
}
|
|
dprintf("MEM: Total %d bytes\n", TotalMem);
|
|
}
|
|
|
|
PUCHAR CallState[] =
|
|
{
|
|
"STATE_CALL_INVALID",
|
|
"STATE_CALL_CLOSED",
|
|
"STATE_CALL_IDLE",
|
|
"STATE_CALL_OFFHOOK",
|
|
"STATE_CALL_OFFERING",
|
|
"STATE_CALL_PAC_OFFERING",
|
|
"STATE_CALL_PAC_WAIT",
|
|
"STATE_CALL_DIALING",
|
|
"STATE_CALL_PROCEEDING",
|
|
"STATE_CALL_ESTABLISHED",
|
|
"STATE_CALL_WAIT_DISCONNECT",
|
|
"STATE_CALL_CLEANUP"
|
|
};
|
|
|
|
DECLARE_API( calls )
|
|
{
|
|
PPTP_ADAPTER Adapter;
|
|
CALL_SESSION Call;
|
|
ULONG_PTR pCall;
|
|
ULONG_PTR pAdapter = GetExpression("raspptp!pgAdapter");
|
|
ULONG i, StartCall=0, EndCall=0xffff;
|
|
char argbuf[MAX_PATH];
|
|
char arglist[2][MAX_PATH];
|
|
|
|
if (args && *args)
|
|
{
|
|
char *p;
|
|
|
|
strcpy(argbuf, args);
|
|
|
|
i = 0;
|
|
//parsing the arguments
|
|
for (p = mystrtok( argbuf, " \t,;" );
|
|
p && *p && i<2;
|
|
p = mystrtok(NULL, " \t,;"))
|
|
{
|
|
strcpy(&arglist[i++][0],p);
|
|
}
|
|
if (i>0)
|
|
{
|
|
StartCall = EndCall = atoi(arglist[0]);
|
|
}
|
|
if (i>1)
|
|
{
|
|
EndCall = atoi(arglist[1]);
|
|
}
|
|
}
|
|
|
|
if (!GetData(&pAdapter,
|
|
pAdapter,
|
|
sizeof(pAdapter),
|
|
"PPTP_ADAPTER*"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
if (!pAdapter)
|
|
{
|
|
dprintf("no adapter\n");
|
|
return;
|
|
}
|
|
if (!GetData(&Adapter,
|
|
pAdapter,
|
|
sizeof(Adapter),
|
|
"PPTP_ADAPTER"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
dprintf("Adapter:%08x %d calls\n", pAdapter, Adapter.Info.Endpoints);
|
|
for (i=StartCall; i<Adapter.Info.Endpoints && i<=EndCall; i++)
|
|
{
|
|
if (!GetData(&pCall,
|
|
((ULONG_PTR)Adapter.pCallArray)+i*sizeof(ULONG_PTR),
|
|
sizeof(pCall),
|
|
"CALL_SESSION*"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
if (pCall)
|
|
{
|
|
if (!GetData(&Call,
|
|
pCall,
|
|
sizeof(Call),
|
|
"CALL_SESSION"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
dprintf("Call %d:%08x Ctl:%08x State:%s Inbound:%d Open:%d\n",
|
|
i, pCall, Call.pCtl, CallState[Call.State], Call.Inbound, Call.Open);
|
|
dprintf(" htCall:%08x DeviceId:%d SN:%d Link:%08x\n",
|
|
Call.hTapiCall, Call.DeviceId, Call.SerialNumber, Call.NdisLinkContext);
|
|
dprintf(" Remote->ID:%04x Seq:%08x Ack:%08x Addr:%08x\n",
|
|
Call.Remote.CallId,
|
|
Call.Remote.SequenceNumber,
|
|
Call.Remote.AckNumber,
|
|
Call.Remote.Address.Address[0].Address[0].in_addr);
|
|
dprintf(" Packet->ID:%04x Seq:%08x Ack:%08x\n",
|
|
Call.Packet.CallId,
|
|
Call.Packet.SequenceNumber,
|
|
Call.Packet.AckNumber);
|
|
dprintf(" Close->Expedited:%d Checklist:%x\n",
|
|
Call.Close.Expedited, Call.Close.Checklist);
|
|
}
|
|
else
|
|
{
|
|
dprintf("Call %d:freed\n", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
PUCHAR CtlState[] =
|
|
{
|
|
"STATE_CTL_INVALID",
|
|
"STATE_CTL_LISTEN",
|
|
"STATE_CTL_DIALING",
|
|
"STATE_CTL_WAIT_REQUEST",
|
|
"STATE_CTL_WAIT_REPLY",
|
|
"STATE_CTL_ESTABLISHED",
|
|
"STATE_CTL_WAIT_STOP",
|
|
"STATE_CTL_CLEANUP"
|
|
};
|
|
|
|
DECLARE_API( ctls )
|
|
{
|
|
PPTP_ADAPTER Adapter;
|
|
LIST_ENTRY ListEntry;
|
|
PLIST_ENTRY ListHead;
|
|
char argbuf[ MAX_PATH ];
|
|
ULONG_PTR pAdapter = GetExpression("raspptp!pgAdapter");
|
|
|
|
if (!GetData(&pAdapter,
|
|
pAdapter,
|
|
sizeof(pAdapter),
|
|
"PPTP_ADAPTER*"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
if (!pAdapter)
|
|
{
|
|
dprintf("no adapter\n");
|
|
return;
|
|
}
|
|
if (!GetData(&Adapter,
|
|
pAdapter,
|
|
sizeof(Adapter),
|
|
"PPTP_ADAPTER"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
ListHead = (PLIST_ENTRY)(((ULONG_PTR)&Adapter.ControlTunnelList) - ((ULONG_PTR)&Adapter) + pAdapter);
|
|
ListEntry = Adapter.ControlTunnelList;
|
|
|
|
while (ListHead!=ListEntry.Flink)
|
|
{
|
|
CONTROL_TUNNEL Ctl;
|
|
if (!GetData(&Ctl,
|
|
(ULONG_PTR)ListEntry.Flink,
|
|
sizeof(CONTROL_TUNNEL),
|
|
"CONTROL_TUNNEL"))
|
|
{
|
|
dprintf("error\n");
|
|
return;
|
|
}
|
|
|
|
dprintf("CTL:%08x Sig:%08x State:%s Refs:%d Cleanup:%x Inbound:%d\n",
|
|
ListEntry.Flink, Ctl.Signature, CtlState[Ctl.State], Ctl.Reference.Count, Ctl.Cleanup, Ctl.Inbound);
|
|
ListEntry = Ctl.ListEntry;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpIrpList(LIST_ENTRY *pIrpList)
|
|
{
|
|
LIST_ENTRY IrpList, *pListEntry, ListEntry;
|
|
IRP *pIrp;
|
|
|
|
if (!GetData(&IrpList,
|
|
(DWORD_PTR) pIrpList,
|
|
sizeof(LIST_ENTRY), "LIST_ENTRY"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (pListEntry = IrpList.Flink;
|
|
pListEntry != pIrpList;
|
|
pListEntry = ListEntry.Flink)
|
|
{
|
|
|
|
if (!GetData(&ListEntry,
|
|
(DWORD_PTR) pListEntry,
|
|
sizeof(LIST_ENTRY), "LIST_ENTRY"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
dprintf(" %x\n", pIrp);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WinDbgExtensionDllInit(
|
|
PWINDBG_EXTENSION_APIS lpExtensionApis,
|
|
USHORT MajorVersion,
|
|
USHORT MinorVersion
|
|
)
|
|
{
|
|
ExtensionApis = *lpExtensionApis;
|
|
|
|
SavedMajorVersion = MajorVersion;
|
|
SavedMinorVersion = MinorVersion;
|
|
ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
|
|
}
|
|
|
|
DECLARE_API( version )
|
|
{
|
|
#if DBG
|
|
PCSTR kind = "Checked";
|
|
#else
|
|
PCSTR kind = "Free";
|
|
#endif
|
|
|
|
dprintf(
|
|
"%s SMB Extension dll for Build %d debugging %s kernel for Build %d\n",
|
|
kind,
|
|
VER_PRODUCTBUILD,
|
|
SavedMajorVersion == 0x0c ? "Checked" : "Free",
|
|
SavedMinorVersion
|
|
);
|
|
}
|
|
|
|
VOID
|
|
CheckVersion(
|
|
VOID
|
|
)
|
|
{
|
|
#if DBG
|
|
if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
|
|
dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
|
|
VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
|
|
}
|
|
#else
|
|
if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
|
|
dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
|
|
VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LPEXT_API_VERSION
|
|
ExtensionApiVersion(
|
|
VOID
|
|
)
|
|
{
|
|
return &ApiVersion;
|
|
}
|