diff options
Diffstat (limited to 'private/nw/nwlib/exchange.c')
-rw-r--r-- | private/nw/nwlib/exchange.c | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/private/nw/nwlib/exchange.c b/private/nw/nwlib/exchange.c new file mode 100644 index 000000000..52f34ad38 --- /dev/null +++ b/private/nw/nwlib/exchange.c @@ -0,0 +1,571 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + exchange.c + +Abstract: + + Contains routine which packages the request buffer, makes + the NCP request, and unpackages the response buffer. + +Author: + + Hans Hurvig (hanshu) Aug-1992 Created + Colin Watson (colinw) 19-Dec-1992 + Rita Wong (ritaw) 11-Mar-1993 FSCtl version + +Environment: + + +Revision History: + + +--*/ + + +#include <procs.h> + +NTSTATUS +NwlibMakeNcp( + IN HANDLE DeviceHandle, + IN ULONG FsControlCode, + IN ULONG RequestBufferSize, + IN ULONG ResponseBufferSize, + IN PCHAR FormatString, + ... // Arguments to FormatString + ) +/*++ + +Routine Description: + + This function converts the input arguments into an NCP request buffer + based on the format specified in FormatString (e.g. takes a word + and writes it in hi-lo format in the request buffer as required by + an NCP). + + It then makes the NCP call via the NtFsControlFile API. + + The FormatString also specifies how to convert the fields in the + response buffer from the completed NCP call into the output + arguments. + + The FormatString takes the form of "xxxx|yyyy" where each 'x' + indicates an input argument to convert from, and each 'y' indicates + an output argument to convert into. The '|' character separates + the input format from the output format specifications. + +Arguments: + + DeviceHandle - Supplies a handle to the network file system driver + which will be making the network request. This function + assumes that the handle was opened for synchronouse I/O access. + + FsControlCode - Supplies the control code which determines the + NCP. + + RequestBufferSize - Supplies the size of the request buffer in + bytes to be allocated by this routine. + + ResponseBufferSize - Supplies the size of the response buffer in + bytes to be allocated by this routine. + + 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* ) + '-' zero/skip byte ( void ) + '=' zero/skip word ( void ) + ._. zero/skip string ( word ) + 'p' pstring ( char* ) + 'P' DBCS pstring ( char* ) + 'c' cstring ( char* ) + 'C' cstring followed skip word ( char*, word ) + 'r' raw bytes ( byte*, word ) + 'R' DBCS raw bytes ( byte*, word ) + 'u' p unicode string ( UNICODE_STRING * ) + 'U' p uppercase string( UNICODE_STRING * ) + 'W' word n followed by an array of word[n] ( word, word* ) + +Return Value: + + Return code from the NCP call. + +--*/ +{ + NTSTATUS status; + + va_list Arguments; + PCHAR z; + WORD t = 1; + ULONG data_size; + + LPBYTE RequestBuffer = NULL; + LPBYTE ResponseBuffer; + + IO_STATUS_BLOCK IoStatusBlock; + DWORD ReturnedDataSize; + + + // + // Allocate memory for request and response buffers. + // + RequestBuffer = LocalAlloc( + LMEM_ZEROINIT, + RequestBufferSize + ResponseBufferSize + ); + + if (RequestBuffer == NULL) { + KdPrint(("NWLIB: NwlibMakeNcp LocalAlloc failed %lu\n", GetLastError())); + return STATUS_NO_MEMORY; + } + + ResponseBuffer = (LPBYTE) ((ULONG) RequestBuffer + RequestBufferSize); + + + va_start( Arguments, FormatString ); + + // + // Convert the input arguments into request packet. + // + z = FormatString; + + data_size = 0; + + while ( *z && *z != '|') + { + switch ( *z ) + { + case '=': + RequestBuffer[data_size++] = 0; + case '-': + RequestBuffer[data_size++] = 0; + break; + + case '_': + { + WORD l = va_arg ( Arguments, WORD ); + if (data_size + l > RequestBufferSize) + { + KdPrint(("NWLIB: NwlibMakeNcp case '_' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + while ( l-- ) + RequestBuffer[data_size++] = 0; + break; + } + + case 'b': + RequestBuffer[data_size++] = va_arg ( Arguments, BYTE ); + break; + + case 'w': + { + WORD w = va_arg ( Arguments, WORD ); + RequestBuffer[data_size++] = (BYTE) (w >> 8); + RequestBuffer[data_size++] = (BYTE) (w >> 0); + break; + } + + case 'd': + { + DWORD d = va_arg ( Arguments, DWORD ); + RequestBuffer[data_size++] = (BYTE) (d >> 24); + RequestBuffer[data_size++] = (BYTE) (d >> 16); + RequestBuffer[data_size++] = (BYTE) (d >> 8); + RequestBuffer[data_size++] = (BYTE) (d >> 0); + break; + } + + case 'c': + { + char* c = va_arg ( Arguments, char* ); + WORD l = strlen( c ); + if (data_size + l > RequestBufferSize) + { + KdPrint(("NWLIB: NwlibMakeNcp case 'c' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + RtlCopyMemory( &RequestBuffer[data_size], c, l+1 ); + data_size += l + 1; + break; + } + + case 'C': + { + char* c = va_arg ( Arguments, char* ); + WORD l = va_arg ( Arguments, WORD ); + WORD len = strlen( c ) + 1; + if (data_size + l > RequestBufferSize) + { + KdPrint(("NWLIB: NwlibMakeNcp case 'C' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + + RtlCopyMemory( &RequestBuffer[data_size], c, len > l? l : len); + data_size += l; + RequestBuffer[data_size-1] = 0; + break; + } + + case 'P': + case 'p': + { + char* c = va_arg ( Arguments, char* ); + BYTE l = strlen( c ); + char* p; + + if (data_size + l > RequestBufferSize) + { + KdPrint(("NWLIB: NwlibMakeNcp case 'p' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + RequestBuffer[data_size++] = l; + RtlCopyMemory( (p=(char*)&RequestBuffer[data_size]), c, l ); + data_size += l; + + // + // Map Japanese special chars + // + if (*z == 'P') { + MapSpecialJapaneseChars(p, (WORD)l); + } + + break; + } + + case 'u': + { + PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING ); + OEM_STRING OemString; + ULONG Length; + + // + // Calculate required string length, excluding trailing NUL. + // + + Length = RtlUnicodeStringToOemSize( pUString ) - 1; + ASSERT( Length < 0x100 ); + + if ( data_size + Length > RequestBufferSize ) { + KdPrint(("NWLIB: NwlibMakeNcp case 'u' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + + RequestBuffer[data_size++] = (UCHAR)Length; + OemString.Buffer = &RequestBuffer[data_size]; + OemString.MaximumLength = (USHORT)Length + 1; + + // + // BUGBUG: The following should call RtlUnicodeStringToCountedOemString + // but this routine is not exported by ntdll.dll so we can't get to it. + // + status = RtlUnicodeStringToOemString( &OemString, pUString, FALSE ); + ASSERT( NT_SUCCESS( status )); + data_size += (USHORT)Length; + break; + } + + case 'U': + { + // + // UPPERCASE the string, copy it from unicode to the packet + // + + PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING ); + UNICODE_STRING UUppercaseString; + OEM_STRING OemString; + ULONG Length; + + status = RtlUpcaseUnicodeString(&UUppercaseString, pUString, TRUE); + if ( status ) + { + goto CleanExit; + } + + pUString = &UUppercaseString; + + // + // Calculate required string length, excluding trailing NUL. + // + + Length = RtlUnicodeStringToOemSize( pUString ) - 1; + ASSERT( Length < 0x100 ); + + if ( data_size + Length > RequestBufferSize ) { + KdPrint(("NWLIB: NwlibMakeNcp case 'U' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + + RequestBuffer[data_size++] = (UCHAR)Length; + OemString.Buffer = &RequestBuffer[data_size]; + OemString.MaximumLength = (USHORT)Length + 1; + + // + // BUGBUG: The following should call RtlUnicodeStringToCountedOemString + // but this routine is not exported by ntdll.dll so we can't get to it. + // + status = RtlUnicodeStringToOemString( &OemString, pUString, FALSE ); + ASSERT( NT_SUCCESS( status )); + + RtlFreeUnicodeString( &UUppercaseString ); + + data_size += (USHORT)Length; + break; + } + + case 'R': + case 'r': + { + BYTE* b = va_arg ( Arguments, BYTE* ); + WORD l = va_arg ( Arguments, WORD ); + char* c; + + if ( data_size + l > RequestBufferSize ) + { + KdPrint(("NWLIB: NwlibMakeNcp case 'r' request buffer too small\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + + RtlCopyMemory( (c=(char*)&RequestBuffer[data_size]), b, l ); + data_size += l; + + // + // Map Japanese special chars + // + if (*z == 'R') { + MapSpecialJapaneseChars(c, (WORD)l); + } + + break; + } + + default: + KdPrint(("NWLIB: NwlibMakeNcp invalid request field, %x\n", *z)); + ASSERT(FALSE); + } + + if ( data_size > RequestBufferSize ) + { + KdPrint(("NWLIB: NwlibMakeNcp too much request data\n")); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanExit; + } + + + z++; + } + + + // + // Make the NCP request + // + status = NtFsControlFile( + DeviceHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + FsControlCode, + (PVOID) RequestBuffer, + RequestBufferSize, + (PVOID) ResponseBuffer, + ResponseBufferSize + ); + + if (status == STATUS_SUCCESS) { + status = IoStatusBlock.Status; + } + + if (status != STATUS_SUCCESS) { + +#if 0 + if (! NT_SUCCESS(status)) { + KdPrint(("NWLIB: NwlibMakeNcp: NtFsControlFile returns x%08lx\n", status)); + } +#endif + + goto CleanExit; + } + + + ReturnedDataSize = IoStatusBlock.Information; // Number of bytes returned + // in ResponseBuffer + + + // + // Convert the response packet into output arguments. + // + + data_size = 0; + + if (*z && *z == '|') { + z++; + } + + while ( *z ) + { + switch ( *z ) + { + case '-': + data_size += 1; + break; + + case '=': + data_size += 2; + break; + + case '_': + { + WORD l = va_arg ( Arguments, WORD ); + data_size += l; + break; + } + + case 'b': + { + BYTE* b = va_arg ( Arguments, BYTE* ); + *b = ResponseBuffer[data_size++]; + break; + } + + case 'w': + { + BYTE* b = va_arg ( Arguments, BYTE* ); + b[1] = ResponseBuffer[data_size++]; + b[0] = ResponseBuffer[data_size++]; + break; + } + + case 'd': + { + BYTE* b = va_arg ( Arguments, BYTE* ); + b[3] = ResponseBuffer[data_size++]; + b[2] = ResponseBuffer[data_size++]; + b[1] = ResponseBuffer[data_size++]; + b[0] = ResponseBuffer[data_size++]; + break; + } + + case 'c': + { + char* c = va_arg ( Arguments, char* ); + WORD l = strlen( &ResponseBuffer[data_size] ); + if ( data_size+l+1 < ReturnedDataSize ) { + RtlCopyMemory( c, &ResponseBuffer[data_size], l+1 ); + } + data_size += l+1; + break; + } + + case 'C': + { + char* c = va_arg ( Arguments, char* ); + WORD l = va_arg ( Arguments, WORD ); + WORD len = strlen( &ResponseBuffer[data_size] ) + 1; + + if ( data_size + l < ReturnedDataSize ) { + RtlCopyMemory( c, &ResponseBuffer[data_size], len > l ? l :len); + } + c[l-1] = 0; + data_size += l; + break; + + } + + case 'P': + case 'p': + { + char* c = va_arg ( Arguments, char* ); + BYTE l = ResponseBuffer[data_size++]; + if ( data_size+l <= ReturnedDataSize ) { + RtlCopyMemory( c, &ResponseBuffer[data_size], l ); + c[l] = 0; + } + data_size += l; + + // + // Unmap Japanese special chars + // + if (*z == 'P') { + UnmapSpecialJapaneseChars(c, l); + } + + break; + } + + case 'R': + case 'r': + { + BYTE* b = va_arg ( Arguments, BYTE* ); + WORD l = va_arg ( Arguments, WORD ); + RtlCopyMemory( b, &ResponseBuffer[data_size], l ); + data_size += l; + + // + // Unmap Japanese special chars + // + if (*z == 'R') { + UnmapSpecialJapaneseChars(b, l); + } + break; + } + + case 'W': + { + BYTE* b = va_arg ( Arguments, BYTE* ); + BYTE* w = va_arg ( Arguments, BYTE* ); + WORD i; + + b[1] = ResponseBuffer[data_size++]; + b[0] = ResponseBuffer[data_size++]; + + for ( i = 0; i < ((WORD) *b); i++, w += sizeof(WORD) ) + { + w[1] = ResponseBuffer[data_size++]; + w[0] = ResponseBuffer[data_size++]; + } + break; + } + + default: + KdPrint(("NWLIB: NwlibMakeNcp invalid response field, %x\n", *z)); + ASSERT(FALSE); + } + + if ( data_size > ReturnedDataSize ) + { + KdPrint(("NWLIB: NwlibMakeNcp not enough response data\n")); + status = STATUS_UNSUCCESSFUL; + goto CleanExit; + } + + z++; + } + + status = STATUS_SUCCESS; + +CleanExit: + if (RequestBuffer != NULL) { + (void) LocalFree((HLOCAL) RequestBuffer); + } + + va_end( Arguments ); + + return status; +} + |