Source code of Windows XP (NT5)
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.

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