summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/fragex.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/fragex.c')
-rw-r--r--private/nw/rdr/fragex.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/private/nw/rdr/fragex.c b/private/nw/rdr/fragex.c
new file mode 100644
index 000000000..948fb09f8
--- /dev/null
+++ b/private/nw/rdr/fragex.c
@@ -0,0 +1,783 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ FragEx.c
+
+Abstract:
+
+ This module implements the fragment exchanger routine for
+ netware directory services access.
+
+Author:
+
+ Cory West [CoryWest] 23-Feb-1995
+
+Revision History:
+
+--*/
+
+#include <stdarg.h>
+#include "Procs.h"
+
+#define Dbg (DEBUG_TRACE_EXCHANGE)
+
+#pragma alloc_text( PAGE, FragExWithWait )
+#pragma alloc_text( PAGE, FormatBuf )
+#pragma alloc_text( PAGE, FormatBufS )
+
+NTSTATUS
+_cdecl
+FragExWithWait(
+ IN PIRP_CONTEXT pIrpContext,
+ IN DWORD NdsVerb,
+ IN PLOCKED_BUFFER pReplyBuffer,
+ IN BYTE *NdsRequestStr,
+ ...
+)
+/*
+
+Routine Description:
+
+ Exchanges an NDS request in fragments and collects the fragments
+ of the response. The buffer passed in much be locked down for
+ the transport.
+
+Routine Arguments:
+
+ pIrpContext - A pointer to the context information for this IRP.
+ NdsVerb - The verb for that indicates the request.
+
+ pReplyBuffer - The locked down reply buffer.
+
+ NdsReqestStr - The format string for the arguments to this NDS request.
+ Arguments - The arguments that satisfy the NDS format string.
+
+Return Value:
+
+ NTSTATUS - Status of the exchange, but not the result code in the packet.
+
+*/
+{
+
+ NTSTATUS Status;
+
+ BYTE *NdsRequestBuf;
+ DWORD NdsRequestLen;
+
+ BYTE *NdsRequestFrag, *NdsReplyFrag;
+ DWORD NdsRequestBytesLeft, NdsReplyBytesLeft, NdsReplyLen;
+
+ va_list Arguments;
+
+ PMDL pMdlSendData = NULL,
+ pTxMdlFrag = NULL,
+ pRxMdlFrag = NULL;
+
+ PMDL pOrigMdl;
+ DWORD OrigRxMdlSize;
+
+ DWORD MaxFragSize, SendFragSize;
+ DWORD ReplyFragSize, ReplyFragHandle;
+
+ DWORD NdsFraggerHandle = DUMMY_ITER_HANDLE;
+
+ PAGED_CODE();
+
+ DebugTrace( 0 , Dbg, "Entering FragExWithWait...\n", 0 );
+
+ //
+ // Allocate conversation buffer for the request.
+ //
+
+ NdsRequestBuf = ALLOCATE_POOL( PagedPool, NDS_BUFFER_SIZE );
+
+ if ( !NdsRequestBuf ) {
+
+ DebugTrace( 0, Dbg, "No memory for request buffer...\n", 0 );
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ //
+ // Build the request in our local buffer. Reserve the first
+ // five DWORDs for the NDS request header.
+ //
+
+ if ( NdsRequestStr != NULL ) {
+
+ va_start( Arguments, NdsRequestStr );
+
+ NdsRequestFrag = (BYTE *) NdsRequestBuf + sizeof( NDS_REQUEST_HEADER );
+
+ NdsRequestLen = FormatBuf( NdsRequestFrag,
+ NDS_BUFFER_SIZE - sizeof( NDS_REQUEST_HEADER ),
+ NdsRequestStr,
+ Arguments );
+
+ if ( !NdsRequestLen ) {
+
+ Status = STATUS_UNSUCCESSFUL;
+ goto ExitWithCleanup;
+
+ }
+
+ va_end( Arguments );
+
+ } else {
+
+ NdsRequestLen = 0;
+ }
+
+ //
+ // Pack in the NDS preamble now that we know the length.
+ //
+ // The second DWORD in the preamble is the size of the NDS
+ // request which includes the three DWORDs immediately
+ // following the size in the preamble.
+ //
+
+ MaxFragSize = pIrpContext->pNpScb->BufferSize -
+ ( sizeof( NCP_REQUEST_WITH_SUB ) +
+ sizeof( NDS_REPLY_HEADER ) );
+
+ FormatBufS( NdsRequestBuf,
+ 5 * sizeof( DWORD ),
+ "DDDDD",
+ MaxFragSize, // max fragment size
+ NdsRequestLen + ( 3 * sizeof( DWORD ) ), // request size
+ 0, // fragment flags
+ NdsVerb, // nds verb
+ pReplyBuffer->dwRecvLen ); // reply buffer size
+
+ NdsRequestLen += sizeof( NDS_REQUEST_HEADER );
+
+ //
+ // Map the entire request to the SendData mdl and lock it down.
+ // we'll build partials into this data chunk as we proceed.
+ //
+
+ pMdlSendData = ALLOCATE_MDL( NdsRequestBuf,
+ NdsRequestLen,
+ FALSE,
+ FALSE,
+ NULL );
+
+ if ( !pMdlSendData ) {
+
+ DebugTrace( 0, Dbg, "Failed to allocate the request mdl...\n", 0 );
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitWithCleanup;
+ }
+
+ try {
+
+ MmProbeAndLockPages( pMdlSendData, KernelMode, IoReadAccess );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ DebugTrace( 0, Dbg, "Failed to lock request data in FragExWithWait!\n", 0 );
+ Status = GetExceptionCode();
+ goto ExitWithCleanup;
+
+ }
+
+ //
+ // Allocate space for send and receive partial mdls.
+ //
+
+ pTxMdlFrag = ALLOCATE_MDL( NdsRequestBuf,
+ NdsRequestLen,
+ FALSE,
+ FALSE,
+ NULL );
+
+ if ( !pTxMdlFrag ) {
+
+ DebugTrace( 0, Dbg, "Failed to allocate a tx mdl for this fragment...\n", 0 );
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitWithCleanup;
+
+ }
+
+ pRxMdlFrag = ALLOCATE_MDL( pReplyBuffer->pRecvBufferVa,
+ pReplyBuffer->dwRecvLen,
+ FALSE,
+ FALSE,
+ NULL );
+
+ if ( !pRxMdlFrag ) {
+
+ DebugTrace( 0, Dbg, "Failed to allocate an rx mdl for this fragment...\n", 0 );
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitWithCleanup;
+
+ }
+
+ //
+ // Store the original RxMdl parameters and temporarily shorten it to hold
+ // only the response header.
+ //
+
+ pOrigMdl = pIrpContext->RxMdl->Next;
+ OrigRxMdlSize = MmGetMdlByteCount( pIrpContext->RxMdl );
+ pIrpContext->RxMdl->ByteCount = 16;
+
+ //
+ // The request is formatted, so set our internal pointers
+ // and start the exchange loop.
+ //
+
+ NdsReplyFrag = pReplyBuffer->pRecvBufferVa;
+ NdsReplyBytesLeft = pReplyBuffer->dwRecvLen;
+ NdsReplyLen = 0;
+
+ NdsRequestFrag = NdsRequestBuf;
+ NdsRequestBytesLeft = NdsRequestLen;
+
+ while ( TRUE ) {
+
+ //
+ // If there's more data to send in the request, set up the next MDL frag.
+ //
+
+ if ( NdsRequestBytesLeft ) {
+
+ if ( MaxFragSize < NdsRequestBytesLeft )
+ SendFragSize = MaxFragSize;
+ else
+ SendFragSize = NdsRequestBytesLeft;
+
+ IoBuildPartialMdl( pMdlSendData,
+ pTxMdlFrag,
+ NdsRequestFrag,
+ SendFragSize );
+
+ }
+
+ //
+ // Set up the response partial mdl with the buffer space that we have
+ // left. If we are here and there's no space left in the user's buffer,
+ // we're sort of hosed...
+ //
+
+ if ( !NdsReplyBytesLeft ) {
+
+ DebugTrace( 0, Dbg, "No room for fragment reply.\n", 0 );
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto ExitWithCleanup;
+
+ }
+
+ IoBuildPartialMdl( pReplyBuffer->pRecvMdl,
+ pRxMdlFrag,
+ NdsReplyFrag,
+ NdsReplyBytesLeft );
+
+ pIrpContext->RxMdl->Next = pRxMdlFrag;
+ pRxMdlFrag->Next = NULL;
+
+ //
+ // Do this transaction.
+ //
+
+ SetFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
+
+ if ( NdsRequestBytesLeft ) {
+
+ Status = ExchangeWithWait( pIrpContext,
+ SynchronousResponseCallback,
+ "NDf",
+ NDS_REQUEST, // NDS Function 104
+ NDS_ACTION, // NDS Subfunction 2
+ NdsFraggerHandle, // frag handle from the last response
+ pTxMdlFrag ); // NDS MDL Fragment
+
+ NdsRequestBytesLeft -= SendFragSize;
+ NdsRequestFrag = (LPBYTE) NdsRequestFrag + SendFragSize;
+ MmPrepareMdlForReuse( pTxMdlFrag );
+
+ //
+ // We may reuse this irp context, so we have to clear the
+ // TxMdl chain (Exchange doesn't do it for us).
+ //
+
+ pIrpContext->TxMdl->Next = NULL;
+
+ } else {
+
+ //
+ // There were no more request bytes to send, so we must have be allowed
+ // to continue to request another response fragment. NdsFraggerHandle
+ // contains the fragger handle from the last response.
+ //
+
+ Status = ExchangeWithWait( pIrpContext,
+ SynchronousResponseCallback,
+ "ND", // We only care about the frag handle
+ NDS_REQUEST, // NDS Function 104
+ NDS_ACTION, // NDS Subfunction 2
+ NdsFraggerHandle ); // the frag handle from last response
+ }
+
+ ClearFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
+
+ //
+ // Success? Get the frag size and frag handle and see.
+ //
+
+ if ( !NT_SUCCESS( Status ) ) {
+
+ DebugTrace( 0, Dbg, "Failed to exchange the fragment.\n", 0 );
+ goto ExitWithCleanup;
+
+ }
+
+ Status = ParseResponse( pIrpContext,
+ pIrpContext->rsp, // mapped into first rxmdl
+ 16, // only 16 bytes available
+ "NDD",
+ &ReplyFragSize,
+ &ReplyFragHandle );
+
+ if ( !NT_SUCCESS( Status ) ) {
+ goto ExitWithCleanup;
+ }
+
+ //
+ // We got that fragment and it's already in our buffer. We have to adjust
+ // the index pointers, reset the MDLs, and continue on. Remember, we don't
+ // have to include space for the fragger handle since we've already got it.
+ //
+
+ ReplyFragSize -= sizeof( DWORD );
+
+ NdsReplyBytesLeft -= ReplyFragSize;
+ NdsReplyFrag = (LPBYTE) NdsReplyFrag + ReplyFragSize;
+ NdsReplyLen += ReplyFragSize;
+ MmPrepareMdlForReuse( pRxMdlFrag );
+
+ //
+ // Inspect the fraghandle.
+ //
+
+ if ( ReplyFragHandle == DUMMY_ITER_HANDLE ) {
+
+ // We are done!
+ //
+ // Invariant: There is a valid NDS response in the NdsReply
+ // and Status is NT_SUCCESS.
+
+ pReplyBuffer->dwBytesWritten = NdsReplyLen;
+ goto ExitWithCleanup;
+
+ } else {
+
+ // There's more coming! Remember the fragger handle and continue.
+
+ NdsFraggerHandle = ReplyFragHandle;
+ }
+
+ }
+
+ DebugTrace( 0, Dbg, "Invalid state in FragExWithWait()\n", 0 );
+
+ExitWithCleanup:
+
+ //
+ // Unlock the request buffer and free its mdl.
+ //
+
+ if ( pMdlSendData ) {
+
+ MmUnlockPages( pMdlSendData );
+ FREE_MDL( pMdlSendData );
+ }
+
+ //
+ // Free the partial mdls.
+ //
+
+ if ( pRxMdlFrag )
+ FREE_MDL( pRxMdlFrag );
+
+ if ( pTxMdlFrag )
+ FREE_MDL( pTxMdlFrag );
+
+ //
+ // Free the request buffer.
+ //
+
+ FREE_POOL( NdsRequestBuf );
+
+ //
+ // Restore the original Irp->RxMdl parameters.
+ //
+
+ pIrpContext->RxMdl->Next = pOrigMdl;
+ pIrpContext->RxMdl->ByteCount = OrigRxMdlSize;
+
+ return Status;
+
+}
+
+int
+_cdecl
+FormatBuf(
+ char *buf,
+ int bufLen,
+ const char *format,
+ va_list args
+)
+/*
+
+Routine Description:
+
+ Formats a buffer according to supplied the format string.
+
+ FormatString - Supplies an ANSI string which describes how to
+ convert from the input arguments into NCP request fields, and
+ from the NCP response fields into the output arguments.
+
+ Field types, request/response:
+
+ 'b' byte ( byte / byte* )
+ 'w' hi-lo word ( word / word* )
+ 'd' hi-lo dword ( dword / dword* )
+ 'W' lo-hi word ( word / word*)
+ 'D' lo-hi dword ( dword / dword*)
+ '-' zero/skip byte ( void )
+ '=' zero/skip word ( void )
+ ._. zero/skip string ( word )
+ 'p' pstring ( char* )
+ 'c' cstring ( char* )
+ 'C' cstring followed skip word ( char*, word )
+ 'V' sized NDS value ( byte *, dword / byte **, dword *)
+ 'S' p unicode string copy as NDS_STRING (UNICODE_STRING *)
+ 's' cstring copy as NDS_STRING (char* / char *, word)
+ 'r' raw bytes ( byte*, word )
+ 'u' p unicode string ( UNICODE_STRING * )
+ 'U' p uppercase string( UNICODE_STRING * )
+
+Routine Arguments:
+
+ char *buf - destination buffer.
+ int buflen - length of the destination buffer.
+ char *format - format string.
+ args - args to the format string.
+
+Implementation Notes:
+
+ This comes almost verbatim from the Win95 source code. It duplicates
+ work in FormatRequest(). Eventually, FormatRequest() should be split
+ into two distinct routines: FormatBuffer() and MakeRequest().
+
+*/
+{
+ ULONG ix;
+
+ NTSTATUS status;
+ const char *z = format;
+
+ PAGED_CODE();
+
+ //
+ // Convert the input arguments into request packet.
+ //
+
+ ix = 0;
+
+ while ( *z )
+ {
+ switch ( *z )
+ {
+ case '=':
+ buf[ix++] = 0;
+ case '-':
+ buf[ix++] = 0;
+ break;
+
+ case '_':
+ {
+ WORD l = va_arg ( args, WORD );
+ if (ix + (ULONG)l > (ULONG)bufLen)
+ {
+#ifdef NWDBG
+ DbgPrintf( "FormatBuf case '_' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+ while ( l-- )
+ buf[ix++] = 0;
+ break;
+ }
+
+ case 'b':
+ buf[ix++] = va_arg ( args, BYTE );
+ break;
+
+ case 'w':
+ {
+ WORD w = va_arg ( args, WORD );
+ buf[ix++] = (BYTE) (w >> 8);
+ buf[ix++] = (BYTE) (w >> 0);
+ break;
+ }
+
+ case 'd':
+ {
+ DWORD d = va_arg ( args, DWORD );
+ buf[ix++] = (BYTE) (d >> 24);
+ buf[ix++] = (BYTE) (d >> 16);
+ buf[ix++] = (BYTE) (d >> 8);
+ buf[ix++] = (BYTE) (d >> 0);
+ break;
+ }
+
+ case 'W':
+ {
+ WORD w = va_arg(args, WORD);
+ (* (WORD *)&buf[ix]) = w;
+ ix += 2;
+ break;
+ }
+
+ case 'D':
+ {
+ DWORD d = va_arg (args, DWORD);
+ (* (DWORD *)&buf[ix]) = d;
+ ix += 4;
+ break;
+ }
+
+ case 'c':
+ {
+ char* c = va_arg ( args, char* );
+ WORD l = strlen( c );
+ if (ix + (ULONG)l > (ULONG)bufLen)
+ {
+#ifdef NWDBG
+ DbgPrintf( "FormatBuf case 'c' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+ RtlCopyMemory( &buf[ix], c, l+1 );
+ ix += l + 1;
+ break;
+ }
+
+ case 'C':
+ {
+ char* c = va_arg ( args, char* );
+ WORD l = va_arg ( args, WORD );
+ WORD len = strlen( c ) + 1;
+ if (ix + (ULONG)l > (ULONG)bufLen)
+ {
+#ifdef NWDBG
+ DbgPrintf( "FormatBuf 'C' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+
+ RtlCopyMemory( &buf[ix], c, len > l? l : len);
+ ix += l;
+ buf[ix-1] = 0;
+ break;
+ }
+
+ case 'p':
+ {
+ char* c = va_arg ( args, char* );
+ BYTE l = strlen( c );
+ if (ix + (ULONG)l +1 > (ULONG)bufLen)
+ {
+#ifdef NWDBG
+ DbgPrintf( "FormatBuf case 'p' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+ buf[ix++] = l;
+ RtlCopyMemory( &buf[ix], c, l );
+ ix += l;
+ break;
+ }
+
+ case 'u':
+ {
+ PUNICODE_STRING pUString = va_arg ( args, PUNICODE_STRING );
+ OEM_STRING OemString;
+ ULONG Length;
+
+ //
+ // Calculate required string length, excluding trailing NUL.
+ //
+
+ Length = RtlUnicodeStringToOemSize( pUString ) - 1;
+ ASSERT( Length < 0x100 );
+
+ if ( ix + Length > (ULONG)bufLen ) {
+#ifdef NWDBG
+ DbgPrint( "FormatBuf case 'u' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+
+ buf[ix++] = (UCHAR)Length;
+ OemString.Buffer = &buf[ix];
+ OemString.MaximumLength = (USHORT)Length + 1;
+
+ status = RtlUnicodeStringToOemString( &OemString, pUString, FALSE );
+ ASSERT( NT_SUCCESS( status ));
+ ix += (USHORT)Length;
+ break;
+ }
+
+ case 'S':
+ {
+ PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING);
+ ULONG Length, rLength;
+
+ Length = pUString->Length;
+ if (ix + Length + sizeof(Length) + sizeof( WCHAR ) > (ULONG)bufLen) {
+ DebugTrace( 0, Dbg, "FormatBuf: case 'S' request buffer too small.\n", 0 );
+ goto ErrorExit;
+ }
+
+ //
+ // The VLM client uses the rounded up length and it seems to
+ // make a difference! Also, don't forget that NDS strings have
+ // to be NULL terminated.
+ //
+
+ rLength = ROUNDUP4(Length + sizeof( WCHAR ));
+ *((DWORD *)&buf[ix]) = rLength;
+ ix += 4;
+ RtlCopyMemory(&buf[ix], pUString->Buffer, Length);
+ ix += Length;
+ rLength -= Length;
+ RtlFillMemory( &buf[ix], rLength, '\0' );
+ ix += rLength;
+ break;
+
+ }
+
+ case 's':
+ {
+ PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING);
+ ULONG Length, rLength;
+
+ Length = pUString->Length;
+ if (ix + Length + sizeof(Length) + sizeof( WCHAR ) > (ULONG)bufLen) {
+ DebugTrace( 0, Dbg, "FormatBuf: case 's' request buffer too small.\n", 0 );
+ goto ErrorExit;
+ }
+
+ //
+ // Don't use the padded size here, only the NDS null terminator.
+ //
+
+ rLength = Length + sizeof( WCHAR );
+ *((DWORD *)&buf[ix]) = rLength;
+ ix += 4;
+ RtlCopyMemory(&buf[ix], pUString->Buffer, Length);
+ ix += Length;
+ rLength -= Length;
+ RtlFillMemory( &buf[ix], rLength, '\0' );
+ ix += rLength;
+ break;
+
+
+ }
+
+ case 'V':
+ {
+ // too similar to 'S' - should be combined
+ BYTE* b = va_arg ( args, BYTE* );
+ DWORD l = va_arg ( args, DWORD );
+ if ( ix + l + sizeof(DWORD) > (ULONG)
+ bufLen )
+ {
+#ifdef NWDBG
+ DbgPrint( "FormatBuf case 'V' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+ *((DWORD *)&buf[ix]) = l;
+ ix += sizeof(DWORD);
+ RtlCopyMemory( &buf[ix], b, l );
+ l = ROUNDUP4(l);
+ ix += l;
+ break;
+ }
+
+ case 'r':
+ {
+ BYTE* b = va_arg ( args, BYTE* );
+ WORD l = va_arg ( args, WORD );
+ if ( ix + l > (ULONG)bufLen )
+ {
+#ifdef NWDBG
+ DbgPrint( "FormatBuf case 'r' request buffer too small.\n" );
+#endif
+ goto ErrorExit;
+ }
+ RtlCopyMemory( &buf[ix], b, l );
+ ix += l;
+ break;
+ }
+
+ default:
+
+#ifdef NWDBG
+ DbgPrint( "FormatBuf invalid request field, %x.\n", *z );
+#endif
+ ;
+
+ }
+
+ if ( ix > (ULONG)bufLen )
+ {
+#ifdef NWDBG
+ DbgPrint( "FormatBuf: too much request data.\n" );
+#endif
+ goto ErrorExit;
+ }
+
+
+ z++;
+ }
+
+ return(ix);
+
+ErrorExit:
+ return 0;
+}
+
+
+
+int
+_cdecl
+FormatBufS(
+ char *buf,
+ int bufLen,
+ const char *format,
+ ...
+)
+/*++
+ args from the stack
+--*/
+{
+ va_list args;
+ int len;
+
+ PAGED_CODE();
+
+ va_start(args, format);
+ len = FormatBuf(buf, bufLen, format, args);
+ va_end( args );
+
+ return len;
+}
+