diff options
Diffstat (limited to '')
-rw-r--r-- | private/nw/rdr/fragex.c | 783 |
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; +} + |