/*++ Copyright (c) 1987-91 Microsoft Corporation Module Name: Pack.c Abstract: This module just contains RxpPackSendBuffer. Author: John Rogers (JohnRo) 01-Apr-1991 Environment: Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) Requires ANSI C extensions: slash-slash comments, long external names. Revision History: (various NBU people) LanMan 2.x code 01-Apr-1991 JohnRo Created portable version from LanMan 2.x sources. 13-Apr-1991 JohnRo Reduced recompile hits from header files. 03-May-1991 JohnRo Don't use NET_API_FUNCTION for non-APIs. 14-May-1991 JohnRo Clarify that descriptors are 32-bit versions. Use more typedefs. 19-May-1991 JohnRo Make LINT-suggested changes. 13-Jun-1991 JohnRo Allow setinfo when pointers point to current structure. Added debug code. Descriptors are really 16-bit versions. 03-Jul-1991 rfirth Extensive reworking to get variable data area copy working correctly and also remove some code which resulted from bogus assumptions 17-Jul-1991 JohnRo Extracted RxpDebug.h from Rxp.h. 13-Sep-1991 JohnRo Made changes suggested by PC-LINT. 01-Oct-1991 JohnRo More work toward UNICODE. 21-Nov-1991 JohnRo Removed NT dependencies to reduce recompiles. 06-Dec-1991 JohnRo Avoid alignment error on MIPS. --*/ // These must be included first: #include // IN, DWORD, LPTSTR, etc. #include // RpcXlate private header file. // These may be included in any order: #include // RANGE_F(), BUF_INC. #include // NERR_ and ERROR_ equates. #include // NetpAssert(), FORMAT_ equates. #include // NetpMemoryAllocate(), etc. #include // REM_BYTE, etc. #include // IF_DEBUG(). #include // SmbGetUlong(), SmbGetUshort(). #include // strlen() // LPVOID // RxpGetUnalignedPointer( // IN LPVOID * Input // ); // // This macro may have to change if we run on a big-endian machine. #if defined(_WIN64) LPVOID RxpGetUnalignedPointer( LPBYTE Input ) { LARGE_INTEGER pointer; pointer.LowPart = SmbGetUlong( (LPDWORD)Input ); pointer.HighPart = SmbGetUlong( (LPDWORD)(Input+4) ); return (LPVOID)pointer.QuadPart; } #else #define RxpGetUnalignedPointer(Input) \ ( (LPVOID) SmbGetUlong( (LPDWORD) (Input) ) ) #endif NET_API_STATUS RxpPackSendBuffer( IN OUT LPVOID *SendBufferPointerPointer, IN OUT LPDWORD SendBufferLengthPointer, OUT LPBOOL AllocFlagPointer, IN LPDESC DataDesc16, IN LPDESC AuxDesc16, IN DWORD FixedSize16, IN DWORD AuxOffset, IN DWORD AuxLength, IN BOOL SetInfo ) /*++ Routine Description: RxpPackSendBuffer - set up the send buffer for transport across the net. This routine exists specifically to 'undo' some of the work done by RapConvertSingleEntry. The input buffer contains structures and variable data which are to be transmitted to a down-level server. The buffer contains 16-bit data with 32-bit pointers to variable data items WHICH ARE CONTAINED IN THE SAME BUFFER. RapConvertSingleEntry puts variable data in the buffer in the wrong order (see picture). Down-level servers expect variable data to be in the same order as described in the data descriptor strings. They assume this because they fix-up the pointers to the variable data based on knowing the start of the variable data, its type and length. It is for this reason that we must put the strings in the right order and it is this reason which mandates that WE DO NOT HAVE TO SUPPLY GOOD POINTERS OR OFFSETS in the pointer fields, since after this routine, nobody else cares about them We may get this: But down-level needs this: ---------------------- ---------------------- | Primary structure | | Primary structure | | string pointer ------- | string pointer ------- | string pointer ------| | string pointer ------| |--------------------| || |--------------------| || | aux structure | || | aux structure | || | string pointer -----|| | string pointer -----|| | string pointer ----||| | string pointer ----||| |--------------------| |||| |--------------------| |||| | string # 4 | <-||| | string # 1 | <---- |--------------------| ||| |--------------------| ||| | string # 3 | <--|| | string # 2 | <--- |--------------------| || |--------------------| || | string # 2 | <---| | string # 3 | <-- |--------------------| | |--------------------| | | string # 1 | <---- | string # 4 | <- ---------------------- ---------------------- Assumes: 1. Only 1 primary structure in the send buffer 2. The down-level code DOES NOT ACTUALLY USE the pointer fields, but rather, performs its own-fixups & pointer generation based on the data descriptor and RELATIVE POSITION of variable data within the buffer, hence the need for re-ordering * IF THIS ASSUMPTION IS NOT VALID, THIS CODE IS POTENTIALLY BROKEN * 3. The action this routine performs is SPECIFICALLY to re-order the strings in the buffer as shown above. The routine RapConvertSingleEntry was used to pack the structures and variable data into the buffer. There is no spare space in the buffer 4. No other routines after this expect the pointer fields to be valid 5. Strings have already been converted from TCHARs to the correct codepage. 6. The pointers in the structure need not be on DWORD boundaries. Arguments: SendBufferPointerPointer - Points to pointer to the send data. This area will be reallocated if necessary, and the pointer updated. SendBufferLengthPointer - Points to the send data length. The caller sets this to the length of the area at SendBufferPointerPointer. If RxPackSendBuffer reallocates that memory, SendBufferLengthPointer will be updated to reflect the new length. AllocFlagPointer - Points to a BOOL which is set by this routine. To indicate that the send buffer memory has been reallocated. DataDesc16 - Gives descriptor string for data. AuxDesc16 - Gives descriptor string for aux structure. FixedSize16 - Gives size of fixed data structure, in bytes. AuxOffset - Gives position (offset) of N in data structure. (May be NO_AUX_DATA.) AuxLength - Gives size of aux structure in bytes. SetInfo - Indicates whether the API is a setinfo-type (or add-type). Return Value: NET_API_STATUS. --*/ { LPBYTE struct_ptr; LPBYTE c_send_buf; // Caller's (original) send buffer. DWORD c_send_len; // Caller's (original) send buffer size. DWORD buf_length; DWORD to_send_len; DWORD num_aux; LPBYTE data_ptr; BOOL Reallocated; DWORD i,j; LPDESC l_dsc; // Pointer to each field's desc. LPDESC l_str; // Pointer to each desc (DataDesc16, then AuxDesc16). DWORD num_struct; DWORD len; DWORD num_its; DESC_CHAR c; // // we can't perform the string/variable data re-ordering in situ because // one or more of the strings will get trampled. We try and create a copy // of the input buffer to copy the variable data out of // LPBYTE duplicate_buffer = NULL; LPBYTE source_address; // source for copy DBG_UNREFERENCED_PARAMETER(SetInfo); // // Make local copies of the original start and length of the caller's // buffer as the originals may change if NetpMemoryReallocate is used but // they will still be needed for the RANGE_F check. // c_send_buf = *SendBufferPointerPointer; // caller's original buffer c_send_len = *SendBufferLengthPointer; // caller's original buffer length Reallocated = FALSE; // // Due to the specific nature of this routine, these checks should be // redundant since we have already worked out beforehand the requirements // for buffer size. PROVE THIS THEN DELETE THIS CODE // if ((c_send_len < FixedSize16) || (AuxOffset == FixedSize16)) { return NERR_BufTooSmall; } if (AuxOffset != NO_AUX_DATA) { num_aux = (WORD) SmbGetUshort( (LPWORD) (c_send_buf + AuxOffset) ); to_send_len = FixedSize16 + (num_aux * AuxLength); // // see above about redundant code // if (c_send_len < to_send_len) { return NERR_BufTooSmall; } num_its = 2; } else { to_send_len = FixedSize16; num_aux = AuxLength = 0; num_its = 1; /* One structure type to look at */ } IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: initial (fixed) buffer at " FORMAT_LPVOID ":\n", (LPVOID)c_send_buf)); NetpDbgHexDump(c_send_buf, to_send_len); } // // get a duplicate copy of the original buffer. We will use this to copy // the variable data into. This buffer will be returned to the caller, not // the original! // buf_length = c_send_len; // buf_length may be reallocated (?) duplicate_buffer = NetpMemoryAllocate(buf_length); if (duplicate_buffer == NULL) { return ERROR_NOT_ENOUGH_MEMORY; // gasp! } // // Now copy the contents of the original buffer to the duplicate. The // duplicate will have pointers to the data in the original data buffer // that's why we copy from the original to the duplicate, fix up pointers // in the duplicate (even though we don't need to?) and return the // duplicate to the caller // NetpMoveMemory(duplicate_buffer, c_send_buf, c_send_len); // // struct_ptr point into duplicate_buffer. struct_ptr is updated to point // to the next field in the structure for every descriptor token in the // descriptor string // struct_ptr = duplicate_buffer; // // Set up the data pointer to point past fixed length structures. Note this // is in the duplicate structure - that's where we're going to copy the // data // data_ptr = duplicate_buffer + to_send_len; // // for the primary and aux structures, check any pointer designations // in the respective descriptor string and if not NULL copy the data // into the duplicate buffer // l_str = DataDesc16; num_struct = 1; /* Only one primary structure allowed */ for (i = 0; i < num_its; l_str = AuxDesc16, num_struct = num_aux, i++) { for (j = 0 , l_dsc = l_str; j < num_struct; j++, l_dsc = l_str) { for (; (c = *l_dsc) != '\0'; l_dsc++) { IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: processing desc char '" FORMAT_DESC_CHAR "', struct ptr=" FORMAT_LPVOID ".\n", c, struct_ptr )); } // // if the next field in the structure is a pointer type then // if it is not NULL, copy the data into the buffer // if (RapIsPointer(c)) { // // Get pointer value. Note that it may not be aligned! // source_address = (LPBYTE) RxpGetUnalignedPointer( struct_ptr ); IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: " "got source address " FORMAT_LPVOID "\n", (LPVOID) source_address )); } // // Check for NULL pointer. If so then skip over this // field and continue // if (source_address == NULL) { struct_ptr += sizeof(LPBYTE *); IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: " "getting array len\n" )); } // // wind descriptor string forward to next field or // end of string // (void) RapArrayLength(l_dsc, &l_dsc, Both); IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: " "done getting array len\n" )); } } else { // // here if non-NULL pointer // switch( c ) { case REM_ASCIZ : case REM_ASCIZ_TRUNCATABLE: IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: " "getting string len\n" )); } // // Note: we don't have to handle UNICODE here, // as our caller has already done that. // len = strlen( (LPSTR) source_address ) + 1; // // Skip over maximum length count. // (void) RapArrayLength(l_dsc, &l_dsc, Both); IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: " "done getting string len\n" )); } break; case REM_SEND_LENBUF : len = *(LPWORD)source_address; break; default: len = RapArrayLength(l_dsc, &l_dsc, Both); } /* There is data to be copied into the send * buffer so check that it will fit. */ // // This shouldn't happen (I think). If it does, // it suggests we made a miscalculation somewhere. IF // THAT'S THE CASE, FIND THE MISCALCULATION AND REMOVE // THIS CODE // if ((to_send_len += len) > buf_length) { LPBYTE ptr; #ifdef DBG // // let me know what's going on. Again, if this // happens then we should check other code to // ensure it can't be helped. In theory, before // we got here (this routine), we calculated all // the data requirements and allocated a buffer // sufficient to hold everything. Hence we should // not need to re-allocate // NetpKdPrint(("WARNING: attempting re-allocation of " "data buffer. Shouldn't be doing this?\n" )); NetpBreakPoint(); #endif buf_length = to_send_len + BUF_INC; // // note: if this fails then I assume the // original pointer in *SendBufferPointerPointer // is still valid and the caller will still // free it // ptr = (LPBYTE)NetpMemoryReallocate(duplicate_buffer, buf_length); if (!ptr) { NetpMemoryFree(duplicate_buffer); return ERROR_NOT_ENOUGH_MEMORY; // gasp! } // // let caller know buffer he gets back may not // be same as that passed in. Although, this // shouldn't be a problem. // Footnote: *Why* do we indicate this fact? // Reallocated = TRUE; // // re-fix various pointers. We can't make any // assumptions about ptr (can we?) // duplicate_buffer = ptr; struct_ptr = ptr + (struct_ptr - duplicate_buffer); data_ptr = ptr + (data_ptr - duplicate_buffer); } /* There is room for new data in buffer so copy * it and and update the struct and data ptrs */ IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: moving...\n")); } NetpMoveMemory(data_ptr, source_address, len); IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: moved.\n")); } // // update data_ptr to point to the next place to copy // data in duplicate_buffer. Bump the fixed structure // pointer to the next field // data_ptr += len; struct_ptr += sizeof(LPBYTE*); } } else { // // here if the next thing in the descriptor does not identify // a pointer // // // adjust the structure pointer to the next field // struct_ptr += RapGetFieldSize(l_dsc, &l_dsc, Both); } } } } /* Finished process send data, avoid sending the free space at * the end of the buffer by reducing send_data_length to * send_length. */ IF_DEBUG(PACK) { NetpKdPrint(( "RxpPackSendBuffer: final buffer at " FORMAT_LPVOID ":\n", (LPVOID) struct_ptr )); NetpDbgHexDump(duplicate_buffer, to_send_len ); } // // return to the caller the new address of his buffer - this will always // be duplicate_buffer. If we had to reallocate (and we shouldn't!) return // the size of the new buffer // *SendBufferPointerPointer = duplicate_buffer; // May have been reallocated. *SendBufferLengthPointer = to_send_len; *AllocFlagPointer = Reallocated; // caller doesn't need to know this! // // free the caller's original buffer. We now have a buffer which has the // strings in the correct order. However, it is not the same buffer as that // which the user passed in, nor are any of the pointer fields valid. See // assumption 2 above // NetpMemoryFree(c_send_buf); return NERR_Success; } // RxpPackSendBuffer