Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

803 lines
21 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. FragEx.c
  5. Abstract:
  6. This module implements the fragment exchanger routine for
  7. netware directory services access.
  8. Author:
  9. Cory West [CoryWest] 23-Feb-1995
  10. Revision History:
  11. --*/
  12. #include <stdarg.h>
  13. #include "Procs.h"
  14. #define Dbg (DEBUG_TRACE_EXCHANGE)
  15. #pragma alloc_text( PAGE, FragExWithWait )
  16. #pragma alloc_text( PAGE, FormatBuf )
  17. #pragma alloc_text( PAGE, FormatBufS )
  18. NTSTATUS
  19. _cdecl
  20. FragExWithWait(
  21. IN PIRP_CONTEXT pIrpContext,
  22. IN DWORD NdsVerb,
  23. IN PLOCKED_BUFFER pReplyBuffer,
  24. IN BYTE *NdsRequestStr,
  25. ...
  26. )
  27. /*
  28. Routine Description:
  29. Exchanges an NDS request in fragments and collects the fragments
  30. of the response. The buffer passed in much be locked down for
  31. the transport.
  32. Routine Arguments:
  33. pIrpContext - A pointer to the context information for this IRP.
  34. NdsVerb - The verb for that indicates the request.
  35. pReplyBuffer - The locked down reply buffer.
  36. NdsReqestStr - The format string for the arguments to this NDS request.
  37. Arguments - The arguments that satisfy the NDS format string.
  38. Return Value:
  39. NTSTATUS - Status of the exchange, but not the result code in the packet.
  40. */
  41. {
  42. NTSTATUS Status;
  43. BYTE *NdsRequestBuf;
  44. DWORD NdsRequestLen;
  45. BYTE *NdsRequestFrag, *NdsReplyFrag;
  46. DWORD NdsRequestBytesLeft, NdsReplyBytesLeft, NdsReplyLen;
  47. va_list Arguments;
  48. PMDL pMdlSendData = NULL,
  49. pTxMdlFrag = NULL,
  50. pRxMdlFrag = NULL;
  51. PMDL pOrigMdl;
  52. DWORD OrigRxMdlSize;
  53. BOOL bChangedMdl = FALSE;
  54. DWORD MaxFragSize, SendFragSize;
  55. DWORD ReplyFragSize, ReplyFragHandle;
  56. DWORD NdsFraggerHandle = DUMMY_ITER_HANDLE;
  57. // Remove later
  58. ULONG IterationsThroughLoop = 0;
  59. PAGED_CODE();
  60. DebugTrace( 0 , Dbg, "Entering FragExWithWait...\n", 0 );
  61. //
  62. // Allocate conversation buffer for the request.
  63. //
  64. NdsRequestBuf = ALLOCATE_POOL( PagedPool, ( NDS_BUFFER_SIZE * 2 ) );
  65. if ( !NdsRequestBuf ) {
  66. DebugTrace( 0, Dbg, "No memory for request buffer...\n", 0 );
  67. return STATUS_INSUFFICIENT_RESOURCES;
  68. }
  69. //
  70. // Build the request in our local buffer. Reserve the first
  71. // five DWORDs for the NDS request header.
  72. //
  73. if ( NdsRequestStr != NULL ) {
  74. va_start( Arguments, NdsRequestStr );
  75. NdsRequestFrag = (BYTE *) NdsRequestBuf + sizeof( NDS_REQUEST_HEADER );
  76. NdsRequestLen = FormatBuf( NdsRequestFrag,
  77. ( NDS_BUFFER_SIZE * 2 ) - sizeof( NDS_REQUEST_HEADER ),
  78. NdsRequestStr,
  79. Arguments );
  80. if ( !NdsRequestLen ) {
  81. Status = STATUS_UNSUCCESSFUL;
  82. goto ExitWithCleanup;
  83. }
  84. va_end( Arguments );
  85. } else {
  86. NdsRequestLen = 0;
  87. }
  88. //
  89. // Pack in the NDS preamble now that we know the length.
  90. //
  91. // The second DWORD in the preamble is the size of the NDS
  92. // request which includes the three DWORDs immediately
  93. // following the size in the preamble.
  94. //
  95. MaxFragSize = pIrpContext->pNpScb->BufferSize -
  96. ( sizeof( NCP_REQUEST_WITH_SUB ) +
  97. sizeof( NDS_REPLY_HEADER ) );
  98. FormatBufS( NdsRequestBuf,
  99. 5 * sizeof( DWORD ),
  100. "DDDDD",
  101. MaxFragSize, // max fragment size
  102. NdsRequestLen + ( 3 * sizeof( DWORD ) ), // request size
  103. 0, // fragment flags
  104. NdsVerb, // nds verb
  105. pReplyBuffer->dwRecvLen ); // reply buffer size
  106. NdsRequestLen += sizeof( NDS_REQUEST_HEADER );
  107. //
  108. // Map the entire request to the SendData mdl and lock it down.
  109. // we'll build partials into this data chunk as we proceed.
  110. //
  111. pMdlSendData = ALLOCATE_MDL( NdsRequestBuf,
  112. NdsRequestLen,
  113. FALSE,
  114. FALSE,
  115. NULL );
  116. if ( !pMdlSendData ) {
  117. DebugTrace( 0, Dbg, "Failed to allocate the request mdl...\n", 0 );
  118. Status = STATUS_INSUFFICIENT_RESOURCES;
  119. goto ExitWithCleanup;
  120. }
  121. try {
  122. MmProbeAndLockPages( pMdlSendData, KernelMode, IoReadAccess );
  123. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  124. DebugTrace( 0, Dbg, "Failed to lock request data in FragExWithWait!\n", 0 );
  125. Status = GetExceptionCode();
  126. goto ExitWithCleanup;
  127. }
  128. //
  129. // Allocate space for send and receive partial mdls.
  130. //
  131. pTxMdlFrag = ALLOCATE_MDL( NdsRequestBuf,
  132. NdsRequestLen,
  133. FALSE,
  134. FALSE,
  135. NULL );
  136. if ( !pTxMdlFrag ) {
  137. DebugTrace( 0, Dbg, "Failed to allocate a tx mdl for this fragment...\n", 0 );
  138. Status = STATUS_INSUFFICIENT_RESOURCES;
  139. goto ExitWithCleanup;
  140. }
  141. pRxMdlFrag = ALLOCATE_MDL( pReplyBuffer->pRecvBufferVa,
  142. pReplyBuffer->dwRecvLen,
  143. FALSE,
  144. FALSE,
  145. NULL );
  146. if ( !pRxMdlFrag ) {
  147. DebugTrace( 0, Dbg, "Failed to allocate an rx mdl for this fragment...\n", 0 );
  148. Status = STATUS_INSUFFICIENT_RESOURCES;
  149. goto ExitWithCleanup;
  150. }
  151. //
  152. // Store the original RxMdl parameters and temporarily shorten it to hold
  153. // only the response header.
  154. //
  155. pOrigMdl = pIrpContext->RxMdl->Next;
  156. OrigRxMdlSize = MmGetMdlByteCount( pIrpContext->RxMdl );
  157. pIrpContext->RxMdl->ByteCount = 16;
  158. bChangedMdl = TRUE;
  159. //
  160. // The request is formatted, so set our internal pointers
  161. // and start the exchange loop.
  162. //
  163. NdsReplyFrag = pReplyBuffer->pRecvBufferVa;
  164. NdsReplyBytesLeft = pReplyBuffer->dwRecvLen;
  165. NdsReplyLen = 0;
  166. NdsRequestFrag = NdsRequestBuf;
  167. NdsRequestBytesLeft = NdsRequestLen;
  168. while ( TRUE ) {
  169. IterationsThroughLoop++;
  170. //
  171. // If there's more data to send in the request, set up the next MDL frag.
  172. //
  173. if ( NdsRequestBytesLeft ) {
  174. if ( MaxFragSize < NdsRequestBytesLeft )
  175. SendFragSize = MaxFragSize;
  176. else
  177. SendFragSize = NdsRequestBytesLeft;
  178. IoBuildPartialMdl( pMdlSendData,
  179. pTxMdlFrag,
  180. NdsRequestFrag,
  181. SendFragSize );
  182. }
  183. //
  184. // Set up the response partial mdl with the buffer space that we have
  185. // left. If we are here and there's no space left in the user's buffer,
  186. // we're sort of hosed...
  187. //
  188. if ( !NdsReplyBytesLeft ) {
  189. DebugTrace( 0, Dbg, "No room for fragment reply.\n", 0 );
  190. Status = STATUS_BUFFER_OVERFLOW;
  191. goto ExitWithCleanup;
  192. }
  193. ASSERT( NdsReplyBytesLeft <= MmGetMdlByteCount( pRxMdlFrag ) );
  194. IoBuildPartialMdl( pReplyBuffer->pRecvMdl,
  195. pRxMdlFrag,
  196. NdsReplyFrag,
  197. NdsReplyBytesLeft );
  198. pIrpContext->RxMdl->Next = pRxMdlFrag;
  199. pRxMdlFrag->Next = NULL;
  200. //
  201. // Do this transaction.
  202. //
  203. SetFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
  204. if ( NdsRequestBytesLeft ) {
  205. Status = ExchangeWithWait( pIrpContext,
  206. SynchronousResponseCallback,
  207. "NDf",
  208. NDS_REQUEST, // NDS Function 104
  209. NDS_ACTION, // NDS Subfunction 2
  210. NdsFraggerHandle, // frag handle from the last response
  211. pTxMdlFrag ); // NDS MDL Fragment
  212. NdsRequestBytesLeft -= SendFragSize;
  213. NdsRequestFrag = (LPBYTE) NdsRequestFrag + SendFragSize;
  214. MmPrepareMdlForReuse( pTxMdlFrag );
  215. //
  216. // We may reuse this irp context, so we have to clear the
  217. // TxMdl chain (Exchange doesn't do it for us).
  218. //
  219. pIrpContext->TxMdl->Next = NULL;
  220. } else {
  221. //
  222. // There were no more request bytes to send, so we must have be allowed
  223. // to continue to request another response fragment. NdsFraggerHandle
  224. // contains the fragger handle from the last response.
  225. //
  226. Status = ExchangeWithWait( pIrpContext,
  227. SynchronousResponseCallback,
  228. "ND", // We only care about the frag handle
  229. NDS_REQUEST, // NDS Function 104
  230. NDS_ACTION, // NDS Subfunction 2
  231. NdsFraggerHandle ); // the frag handle from last response
  232. }
  233. ClearFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
  234. //
  235. // Success? Get the frag size and frag handle and see.
  236. //
  237. if ((!NT_SUCCESS( Status )) || (pIrpContext->ResponseLength == 0)) {
  238. DebugTrace( 0, Dbg, "Failed to exchange the fragment.\n", 0 );
  239. goto ExitWithCleanup;
  240. }
  241. Status = ParseResponse( pIrpContext,
  242. pIrpContext->rsp, // mapped into first rxmdl
  243. MIN(16, pIrpContext->ResponseLength),
  244. "NDD",
  245. &ReplyFragSize,
  246. &ReplyFragHandle );
  247. if ( !NT_SUCCESS( Status ) ) {
  248. goto ExitWithCleanup;
  249. }
  250. //
  251. // We got that fragment and it's already in our buffer. We have to adjust
  252. // the index pointers, reset the MDLs, and continue on. Remember, we don't
  253. // have to include space for the fragger handle since we've already got it.
  254. //
  255. ReplyFragSize -= sizeof( DWORD );
  256. if (ReplyFragSize > NdsReplyBytesLeft) {
  257. NdsReplyBytesLeft = 0;
  258. } else {
  259. NdsReplyBytesLeft -= ReplyFragSize;
  260. }
  261. NdsReplyFrag = (LPBYTE) NdsReplyFrag + ReplyFragSize;
  262. NdsReplyLen += ReplyFragSize;
  263. MmPrepareMdlForReuse( pRxMdlFrag );
  264. //
  265. // Inspect the fraghandle.
  266. //
  267. if ( ReplyFragHandle == DUMMY_ITER_HANDLE ) {
  268. // We are done!
  269. //
  270. // Invariant: There is a valid NDS response in the NdsReply
  271. // and Status is NT_SUCCESS.
  272. pReplyBuffer->dwBytesWritten = NdsReplyLen;
  273. goto ExitWithCleanup;
  274. } else {
  275. // There's more coming! Remember the fragger handle and continue.
  276. NdsFraggerHandle = ReplyFragHandle;
  277. }
  278. }
  279. DebugTrace( 0, Dbg, "Invalid state in FragExWithWait()\n", 0 );
  280. ExitWithCleanup:
  281. //
  282. // Unlock the request buffer and free its mdl.
  283. //
  284. if ( pMdlSendData ) {
  285. MmUnlockPages( pMdlSendData );
  286. FREE_MDL( pMdlSendData );
  287. }
  288. //
  289. // Free the partial mdls.
  290. //
  291. if ( pRxMdlFrag )
  292. FREE_MDL( pRxMdlFrag );
  293. if ( pTxMdlFrag )
  294. FREE_MDL( pTxMdlFrag );
  295. //
  296. // Free the request buffer.
  297. //
  298. FREE_POOL( NdsRequestBuf );
  299. //
  300. // Restore the original Irp->RxMdl parameters.
  301. //
  302. if ( bChangedMdl )
  303. {
  304. pIrpContext->RxMdl->Next = pOrigMdl;
  305. pIrpContext->RxMdl->ByteCount = OrigRxMdlSize;
  306. }
  307. return Status;
  308. }
  309. int
  310. _cdecl
  311. FormatBuf(
  312. char *buf,
  313. int bufLen,
  314. const char *format,
  315. va_list args
  316. )
  317. /*
  318. Routine Description:
  319. Formats a buffer according to supplied the format string.
  320. FormatString - Supplies an ANSI string which describes how to
  321. convert from the input arguments into NCP request fields, and
  322. from the NCP response fields into the output arguments.
  323. Field types, request/response:
  324. 'b' byte ( byte / byte* )
  325. 'w' hi-lo word ( word / word* )
  326. 'd' hi-lo dword ( dword / dword* )
  327. 'W' lo-hi word ( word / word*)
  328. 'D' lo-hi dword ( dword / dword*)
  329. '-' zero/skip byte ( void )
  330. '=' zero/skip word ( void )
  331. ._. zero/skip string ( word )
  332. 'p' pstring ( char* )
  333. 'c' cstring ( char* )
  334. 'C' cstring followed skip word ( char*, word )
  335. 'V' sized NDS value ( byte *, dword / byte **, dword *)
  336. 'S' p unicode string copy as NDS_STRING (UNICODE_STRING *)
  337. 's' cstring copy as NDS_STRING (char* / char *, word)
  338. 'r' raw bytes ( byte*, word )
  339. 'u' p unicode string ( UNICODE_STRING * )
  340. 'U' p uppercase string( UNICODE_STRING * )
  341. Routine Arguments:
  342. char *buf - destination buffer.
  343. int buflen - length of the destination buffer.
  344. char *format - format string.
  345. args - args to the format string.
  346. Implementation Notes:
  347. This comes almost verbatim from the Win95 source code. It duplicates
  348. work in FormatRequest(). Eventually, FormatRequest() should be split
  349. into two distinct routines: FormatBuffer() and MakeRequest().
  350. */
  351. {
  352. ULONG ix;
  353. NTSTATUS status;
  354. const char *z = format;
  355. PAGED_CODE();
  356. //
  357. // Convert the input arguments into request packet.
  358. //
  359. ix = 0;
  360. while ( *z )
  361. {
  362. switch ( *z )
  363. {
  364. case '=':
  365. buf[ix++] = 0;
  366. case '-':
  367. buf[ix++] = 0;
  368. break;
  369. case '_':
  370. {
  371. WORD l = va_arg ( args, WORD );
  372. if (ix + (ULONG)l > (ULONG)bufLen)
  373. {
  374. #ifdef NWDBG
  375. DbgPrintf( "FormatBuf case '_' request buffer too small.\n" );
  376. #endif
  377. goto ErrorExit;
  378. }
  379. while ( l-- )
  380. buf[ix++] = 0;
  381. break;
  382. }
  383. case 'b':
  384. buf[ix++] = va_arg ( args, BYTE );
  385. break;
  386. case 'w':
  387. {
  388. WORD w = va_arg ( args, WORD );
  389. buf[ix++] = (BYTE) (w >> 8);
  390. buf[ix++] = (BYTE) (w >> 0);
  391. break;
  392. }
  393. case 'd':
  394. {
  395. DWORD d = va_arg ( args, DWORD );
  396. buf[ix++] = (BYTE) (d >> 24);
  397. buf[ix++] = (BYTE) (d >> 16);
  398. buf[ix++] = (BYTE) (d >> 8);
  399. buf[ix++] = (BYTE) (d >> 0);
  400. break;
  401. }
  402. case 'W':
  403. {
  404. WORD w = va_arg(args, WORD);
  405. (* (WORD *)&buf[ix]) = w;
  406. ix += 2;
  407. break;
  408. }
  409. case 'D':
  410. {
  411. DWORD d = va_arg (args, DWORD);
  412. (* (DWORD *)&buf[ix]) = d;
  413. ix += 4;
  414. break;
  415. }
  416. case 'c':
  417. {
  418. char* c = va_arg ( args, char* );
  419. WORD l = (WORD)strlen( c );
  420. if (ix + (ULONG)l > (ULONG)bufLen)
  421. {
  422. #ifdef NWDBG
  423. DbgPrintf( "FormatBuf case 'c' request buffer too small.\n" );
  424. #endif
  425. goto ErrorExit;
  426. }
  427. RtlCopyMemory( &buf[ix], c, l+1 );
  428. ix += l + 1;
  429. break;
  430. }
  431. case 'C':
  432. {
  433. char* c = va_arg ( args, char* );
  434. WORD l = va_arg ( args, WORD );
  435. WORD len = strlen( c ) + 1;
  436. if (ix + (ULONG)l > (ULONG)bufLen)
  437. {
  438. #ifdef NWDBG
  439. DbgPrintf( "FormatBuf 'C' request buffer too small.\n" );
  440. #endif
  441. goto ErrorExit;
  442. }
  443. RtlCopyMemory( &buf[ix], c, len > l? l : len);
  444. ix += l;
  445. buf[ix-1] = 0;
  446. break;
  447. }
  448. case 'p':
  449. {
  450. char* c = va_arg ( args, char* );
  451. BYTE l = (BYTE)strlen( c );
  452. if (ix + (ULONG)l +1 > (ULONG)bufLen)
  453. {
  454. #ifdef NWDBG
  455. DbgPrintf( "FormatBuf case 'p' request buffer too small.\n" );
  456. #endif
  457. goto ErrorExit;
  458. }
  459. buf[ix++] = l;
  460. RtlCopyMemory( &buf[ix], c, l );
  461. ix += l;
  462. break;
  463. }
  464. case 'u':
  465. {
  466. PUNICODE_STRING pUString = va_arg ( args, PUNICODE_STRING );
  467. OEM_STRING OemString;
  468. ULONG Length;
  469. //
  470. // Calculate required string length, excluding trailing NUL.
  471. //
  472. Length = RtlUnicodeStringToOemSize( pUString ) - 1;
  473. ASSERT( Length < 0x100 );
  474. if ( ix + Length > (ULONG)bufLen ) {
  475. #ifdef NWDBG
  476. DbgPrint( "FormatBuf case 'u' request buffer too small.\n" );
  477. #endif
  478. goto ErrorExit;
  479. }
  480. buf[ix++] = (UCHAR)Length;
  481. OemString.Buffer = &buf[ix];
  482. OemString.MaximumLength = (USHORT)Length + 1;
  483. status = RtlUnicodeStringToOemString( &OemString, pUString, FALSE );
  484. ASSERT( NT_SUCCESS( status ));
  485. ix += (USHORT)Length;
  486. break;
  487. }
  488. case 'S':
  489. {
  490. PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING);
  491. ULONG Length, rLength;
  492. Length = pUString->Length;
  493. if (ix + Length + sizeof(Length) + sizeof( WCHAR ) > (ULONG)bufLen) {
  494. DebugTrace( 0, Dbg, "FormatBuf: case 'S' request buffer too small.\n", 0 );
  495. goto ErrorExit;
  496. }
  497. //
  498. // The VLM client uses the rounded up length and it seems to
  499. // make a difference! Also, don't forget that NDS strings have
  500. // to be NULL terminated.
  501. //
  502. rLength = ROUNDUP4(Length + sizeof( WCHAR ));
  503. *((DWORD *)&buf[ix]) = rLength;
  504. ix += 4;
  505. RtlCopyMemory(&buf[ix], pUString->Buffer, Length);
  506. ix += Length;
  507. rLength -= Length;
  508. RtlFillMemory( &buf[ix], rLength, '\0' );
  509. ix += rLength;
  510. break;
  511. }
  512. case 's':
  513. {
  514. PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING);
  515. ULONG Length, rLength;
  516. Length = pUString->Length;
  517. if (ix + Length + sizeof(Length) + sizeof( WCHAR ) > (ULONG)bufLen) {
  518. DebugTrace( 0, Dbg, "FormatBuf: case 's' request buffer too small.\n", 0 );
  519. goto ErrorExit;
  520. }
  521. //
  522. // Don't use the padded size here, only the NDS null terminator.
  523. //
  524. rLength = Length + sizeof( WCHAR );
  525. *((DWORD *)&buf[ix]) = rLength;
  526. ix += 4;
  527. RtlCopyMemory(&buf[ix], pUString->Buffer, Length);
  528. ix += Length;
  529. rLength -= Length;
  530. RtlFillMemory( &buf[ix], rLength, '\0' );
  531. ix += rLength;
  532. break;
  533. }
  534. case 'V':
  535. {
  536. // too similar to 'S' - should be combined
  537. BYTE* b = va_arg ( args, BYTE* );
  538. DWORD l = va_arg ( args, DWORD );
  539. if ( ix + l + sizeof(DWORD) > (ULONG)
  540. bufLen )
  541. {
  542. #ifdef NWDBG
  543. DbgPrint( "FormatBuf case 'V' request buffer too small.\n" );
  544. #endif
  545. goto ErrorExit;
  546. }
  547. *((DWORD *)&buf[ix]) = l;
  548. ix += sizeof(DWORD);
  549. RtlCopyMemory( &buf[ix], b, l );
  550. l = ROUNDUP4(l);
  551. ix += l;
  552. break;
  553. }
  554. case 'r':
  555. {
  556. BYTE* b = va_arg ( args, BYTE* );
  557. WORD l = va_arg ( args, WORD );
  558. if ( ix + l > (ULONG)bufLen )
  559. {
  560. #ifdef NWDBG
  561. DbgPrint( "FormatBuf case 'r' request buffer too small.\n" );
  562. #endif
  563. goto ErrorExit;
  564. }
  565. RtlCopyMemory( &buf[ix], b, l );
  566. ix += l;
  567. break;
  568. }
  569. default:
  570. #ifdef NWDBG
  571. DbgPrint( "FormatBuf invalid request field, %x.\n", *z );
  572. #endif
  573. ;
  574. }
  575. if ( ix > (ULONG)bufLen )
  576. {
  577. #ifdef NWDBG
  578. DbgPrint( "FormatBuf: too much request data.\n" );
  579. #endif
  580. goto ErrorExit;
  581. }
  582. z++;
  583. }
  584. return(ix);
  585. ErrorExit:
  586. return 0;
  587. }
  588. int
  589. _cdecl
  590. FormatBufS(
  591. char *buf,
  592. int bufLen,
  593. const char *format,
  594. ...
  595. )
  596. /*++
  597. args from the stack
  598. --*/
  599. {
  600. va_list args;
  601. int len;
  602. PAGED_CODE();
  603. va_start(args, format);
  604. len = FormatBuf(buf, bufLen, format, args);
  605. va_end( args );
  606. return len;
  607. }