summaryrefslogtreecommitdiffstats
path: root/private/nw/nwlib/exchange.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/nwlib/exchange.c')
-rw-r--r--private/nw/nwlib/exchange.c571
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;
+}
+