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.

5098 lines
132 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. exchange.c
  5. Abstract:
  6. This module implements the File Create routine for the NetWare
  7. redirector called by the dispatch driver.
  8. Author:
  9. Hans Hurvig [hanshu] Aug-1992 Created
  10. Colin Watson [ColinW] 19-Dec-1992
  11. Revision History:
  12. --*/
  13. #include "procs.h"
  14. #include "tdikrnl.h"
  15. #include <STDARG.H>
  16. #define Dbg (DEBUG_TRACE_EXCHANGE)
  17. //
  18. // Exchange.c Global constants
  19. //
  20. // broadcast to socket 0x0452
  21. TA_IPX_ADDRESS SapBroadcastAddress =
  22. {
  23. 1,
  24. sizeof(TA_IPX_ADDRESS), TDI_ADDRESS_TYPE_IPX,
  25. 0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, SAP_SOCKET
  26. };
  27. UCHAR SapPacketType = PACKET_TYPE_SAP;
  28. UCHAR NcpPacketType = PACKET_TYPE_NCP;
  29. extern BOOLEAN WorkerRunning; // From timer.c
  30. ULONG DropCount = 0;
  31. #ifdef NWDBG
  32. int AlwaysAllocateIrp = 1;
  33. #endif
  34. NTSTATUS
  35. CompletionSend(
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PIRP Irp,
  38. IN PVOID Context
  39. );
  40. NTSTATUS
  41. FspGetMessage(
  42. IN PIRP_CONTEXT IrpContext
  43. );
  44. NTSTATUS
  45. CompletionWatchDogSend(
  46. IN PDEVICE_OBJECT DeviceObject,
  47. IN PIRP Irp,
  48. IN PVOID Context
  49. );
  50. USHORT
  51. NextSocket(
  52. IN USHORT OldValue
  53. );
  54. NTSTATUS
  55. FormatRequest(
  56. PIRP_CONTEXT pIrpC,
  57. PEX pEx,
  58. char* f,
  59. va_list a // format specific parameters
  60. );
  61. VOID
  62. ScheduleReconnectRetry(
  63. PIRP_CONTEXT pIrpContext
  64. );
  65. NTSTATUS
  66. CopyIndicatedData(
  67. PIRP_CONTEXT pIrpContext,
  68. PCHAR RspData,
  69. ULONG BytesIndicated,
  70. PULONG BytesTaken,
  71. ULONG ReceiveDatagramFlags
  72. );
  73. NTSTATUS
  74. AllocateReceiveIrp(
  75. PIRP_CONTEXT pIrpContext,
  76. PVOID ReceiveData,
  77. ULONG BytesAvailable,
  78. PULONG BytesAccepted,
  79. PNW_TDI_STRUCT pTdiStruct
  80. );
  81. NTSTATUS
  82. ReceiveIrpCompletion(
  83. PDEVICE_OBJECT DeviceObject,
  84. PIRP Irp,
  85. PVOID Context
  86. );
  87. NTSTATUS
  88. FspProcessServerDown(
  89. PIRP_CONTEXT IrpContext
  90. );
  91. #ifdef ALLOC_PRAGMA
  92. #pragma alloc_text( PAGE, NextSocket )
  93. #pragma alloc_text( PAGE, ExchangeWithWait )
  94. #pragma alloc_text( PAGE, NewRouteRetry )
  95. #ifndef QFE_BUILD
  96. #pragma alloc_text( PAGE1, FspGetMessage )
  97. #pragma alloc_text( PAGE1, Exchange )
  98. #pragma alloc_text( PAGE1, BuildRequestPacket )
  99. #pragma alloc_text( PAGE1, ParseResponse )
  100. #pragma alloc_text( PAGE1, ParseNcpResponse )
  101. #pragma alloc_text( PAGE1, FormatRequest )
  102. #pragma alloc_text( PAGE1, PrepareAndSendPacket )
  103. #pragma alloc_text( PAGE1, PreparePacket )
  104. #pragma alloc_text( PAGE1, SendPacket )
  105. #pragma alloc_text( PAGE1, AppendToScbQueue )
  106. #pragma alloc_text( PAGE1, KickQueue )
  107. #pragma alloc_text( PAGE1, SendNow )
  108. #pragma alloc_text( PAGE1, SetEvent )
  109. #pragma alloc_text( PAGE1, CompletionSend )
  110. #pragma alloc_text( PAGE1, CopyIndicatedData )
  111. #pragma alloc_text( PAGE1, AllocateReceiveIrp )
  112. #pragma alloc_text( PAGE1, ReceiveIrpCompletion )
  113. #pragma alloc_text( PAGE1, VerifyResponse )
  114. #pragma alloc_text( PAGE1, ScheduleReconnectRetry )
  115. #pragma alloc_text( PAGE1, ReconnectRetry )
  116. #pragma alloc_text( PAGE1, NewRouteBurstRetry )
  117. #endif
  118. #endif
  119. #if 0 // Not pageable
  120. ServerDatagramHandler
  121. WatchDogDatagramHandler
  122. SendDatagramHandler
  123. CompletionWatchDogSend
  124. MdlLength
  125. FreeReceiveIrp
  126. FspProcessServerDown
  127. // see ifndef QFE_BUILD above
  128. #endif
  129. NTSTATUS
  130. _cdecl
  131. Exchange(
  132. PIRP_CONTEXT pIrpContext,
  133. PEX pEx,
  134. char* f,
  135. ... // format specific parameters
  136. )
  137. /*++
  138. Routine Description:
  139. This routine is a wrapper for _Exchange. See the comment
  140. in _Exchange for routine and argument description.
  141. --*/
  142. {
  143. va_list Arguments;
  144. NTSTATUS Status;
  145. va_start( Arguments, f );
  146. Status = FormatRequest( pIrpContext, pEx, f, Arguments );
  147. if ( !NT_SUCCESS( Status ) ) {
  148. return( Status );
  149. }
  150. //
  151. // We won't be completing this IRP now, so mark it pending.
  152. //
  153. IoMarkIrpPending( pIrpContext->pOriginalIrp );
  154. //
  155. // Start the packet on it's way to the wire.
  156. //
  157. Status = PrepareAndSendPacket( pIrpContext );
  158. return( Status );
  159. }
  160. NTSTATUS
  161. _cdecl
  162. BuildRequestPacket(
  163. PIRP_CONTEXT pIrpContext,
  164. PEX pEx,
  165. char* f,
  166. ... // format specific parameters
  167. )
  168. /*++
  169. Routine Description:
  170. This routine is a wrapper for FormatRequest. See the comment
  171. in FormatRequest for routine and argument description.
  172. --*/
  173. {
  174. va_list Arguments;
  175. NTSTATUS Status;
  176. va_start( Arguments, f );
  177. Status = FormatRequest( pIrpContext, pEx, f, Arguments );
  178. if ( !NT_SUCCESS( Status ) ) {
  179. return( Status );
  180. }
  181. return( Status );
  182. }
  183. NTSTATUS
  184. _cdecl
  185. ParseResponse(
  186. PIRP_CONTEXT IrpContext,
  187. PUCHAR Response,
  188. ULONG ResponseLength,
  189. char* FormatString,
  190. ... // format specific parameters
  191. )
  192. /*++
  193. Routine Description:
  194. This routine parse an NCP response.
  195. Arguments:
  196. pIrpC - Supplies the irp context for the exchange request. This may
  197. be NULL for generic packet types.
  198. f... - supplies the information needed to create the request to the
  199. server. The first byte indicates the packet type and the
  200. following bytes contain field types.
  201. Packet types:
  202. 'B' Burst primary response ( byte * )
  203. 'N' NCP response ( void )
  204. 'S' Burst secondary response ( byte * )
  205. 'G' Generic packet ( )
  206. Field types, request/response:
  207. 'b' byte ( byte* )
  208. 'w' hi-lo word ( word* )
  209. 'x' ordered word ( word* )
  210. 'd' hi-lo dword ( dword* )
  211. 'e' ordered dword ( dword* )
  212. '-' zero/skip byte ( void )
  213. '=' zero/skip word ( void )
  214. ._. zero/skip string ( word )
  215. 'p' pstring ( char* )
  216. 'p' pstring to Unicode ( UNICODE_STRING * )
  217. 'c' cstring ( char* )
  218. 'r' raw bytes ( byte*, word )
  219. 'R' ASCIIZ to Unicode ( UNICODE_STRING *, word )
  220. Added 3/29/95 by CoryWest:
  221. 'W' lo-hi word ( word / word*)
  222. 'D' lo-hi dword ( dword / dword*)
  223. 'S' unicode string copy as NDS_STRING (UNICODE_STRING *)
  224. 'T' terminal unicode string copy as NDS_STRING (UNICODE_STRING *)
  225. 't' terminal unicode string with the nds null copied
  226. as NDS_STRING (UNICODE_STRING *) (for GetUseName)
  227. Not in use:
  228. 's' cstring copy as NDS_STRING (char* / char *, word)
  229. 'V' sized NDS value ( byte **, dword *)
  230. 'l' what's this?
  231. Return Value:
  232. STATUS - The converted error code from the NCP response.
  233. --*/
  234. {
  235. PEPresponse *pResponseParameters;
  236. PCHAR FormatByte;
  237. va_list Arguments;
  238. NTSTATUS Status = STATUS_SUCCESS;
  239. NTSTATUS NcpStatus;
  240. ULONG Length;
  241. va_start( Arguments, FormatString );
  242. //
  243. // Make sure that we have an IrpContext unless we are doing
  244. // a scan of a generic packet.
  245. //
  246. #ifdef NWDBG
  247. if ( *FormatString != 'G' ) {
  248. ASSERT( IrpContext != NULL );
  249. }
  250. #endif
  251. switch ( *FormatString ) {
  252. //
  253. // NCP response.
  254. //
  255. case 'N':
  256. Length = 8; // The data begins 8 bytes into the packet
  257. pResponseParameters = (PEPresponse *)( ((PEPrequest *)Response) + 1);
  258. //
  259. // If there's a message pending for us on the server and we have
  260. // popups disabled, we won't pick it up, but we should continue
  261. // processing NCPs correctly!
  262. //
  263. if ( ( pResponseParameters->status == 0 ) ||
  264. ( pResponseParameters->status == 0x40 ) ) {
  265. Status = NwErrorToNtStatus( pResponseParameters->error );
  266. } else {
  267. Status = NwConnectionStatusToNtStatus( pResponseParameters->status );
  268. if ( Status == STATUS_REMOTE_DISCONNECT ) {
  269. Stats.ServerDisconnects++;
  270. IrpContext->pNpScb->State = SCB_STATE_RECONNECT_REQUIRED;
  271. }
  272. }
  273. break;
  274. //
  275. // Burst response, first packet
  276. //
  277. case 'B':
  278. {
  279. PNCP_BURST_HEADER BurstResponse = (PNCP_BURST_HEADER)Response;
  280. byte* b = va_arg ( Arguments, byte* );
  281. ULONG Result;
  282. ULONG Offset = BurstResponse->BurstOffset;
  283. *b = BurstResponse->Flags;
  284. Length = 28; // The data begins 28 bytes into the packet
  285. if ( Offset == 0 ) {
  286. //
  287. // This is the first packet in the burst response. Look
  288. // at the result code.
  289. //
  290. // Note that the result DWORD is in lo-hi order.
  291. //
  292. Result = *(ULONG UNALIGNED *)(Response + 36);
  293. switch ( Result ) {
  294. case 0:
  295. case 3: // No data
  296. break;
  297. case 1:
  298. Status = STATUS_DISK_FULL;
  299. break;
  300. case 2: // I/O error
  301. Status = STATUS_UNEXPECTED_IO_ERROR;
  302. break;
  303. default:
  304. Status = NwErrorToNtStatus( (UCHAR)Result );
  305. break;
  306. }
  307. }
  308. break;
  309. }
  310. #if 0
  311. //
  312. // Burst response, secondary packet
  313. //
  314. case 'S':
  315. {
  316. byte* b = va_arg ( Arguments, byte* );
  317. *b = Response[2];
  318. Length = 28; // The data begins 28 bytes into the packet
  319. break;
  320. }
  321. #endif
  322. case 'G':
  323. Length = 0; // The data begins at the start of the packet
  324. break;
  325. default:
  326. ASSERT( FALSE );
  327. Status = STATUS_UNSUCCESSFUL;
  328. break;
  329. }
  330. //
  331. // If this packet contains an error, simply return the error.
  332. //
  333. if ( !NT_SUCCESS( Status ) ) {
  334. return( Status );
  335. }
  336. NcpStatus = Status;
  337. FormatByte = FormatString + 1;
  338. while ( *FormatByte ) {
  339. switch ( *FormatByte ) {
  340. case '-':
  341. Length += 1;
  342. break;
  343. case '=':
  344. Length += 2;
  345. break;
  346. case '_':
  347. {
  348. word l = va_arg ( Arguments, word );
  349. Length += l;
  350. break;
  351. }
  352. case 'b':
  353. {
  354. byte* b = va_arg ( Arguments, byte* );
  355. if (Length + 1 > ResponseLength)
  356. {
  357. Length++;
  358. break;
  359. }
  360. *b = Response[Length++];
  361. break;
  362. }
  363. case 'w':
  364. {
  365. byte* b = va_arg ( Arguments, byte* );
  366. if (Length + 2 > ResponseLength)
  367. {
  368. Length += 2;
  369. break;
  370. }
  371. b[1] = Response[Length++];
  372. b[0] = Response[Length++];
  373. break;
  374. }
  375. case 'x':
  376. {
  377. word* w = va_arg ( Arguments, word* );
  378. if (Length + 2 > ResponseLength)
  379. {
  380. Length += 2;
  381. break;
  382. }
  383. *w = *(word UNALIGNED *)&Response[Length];
  384. Length += 2;
  385. break;
  386. }
  387. case 'd':
  388. {
  389. byte* b = va_arg ( Arguments, byte* );
  390. if (Length + 4 > ResponseLength)
  391. {
  392. Length += 4;
  393. break;
  394. }
  395. b[3] = Response[Length++];
  396. b[2] = Response[Length++];
  397. b[1] = Response[Length++];
  398. b[0] = Response[Length++];
  399. break;
  400. }
  401. case 'e':
  402. {
  403. dword UNALIGNED * d = va_arg ( Arguments, dword* );
  404. if (Length + 4 > ResponseLength)
  405. {
  406. Length += 4;
  407. break;
  408. }
  409. *d = *(dword UNALIGNED *)&Response[Length];
  410. Length += 4;
  411. break;
  412. }
  413. case 'c':
  414. {
  415. char* c = va_arg ( Arguments, char* );
  416. word l = 0;
  417. while ( l + Length < ResponseLength )
  418. {
  419. if ( Response[Length + l] == 0 )
  420. break;
  421. l++;
  422. }
  423. if (Length + l+1 > ResponseLength)
  424. {
  425. // reached end of buffer without finding terminiating NULL
  426. Length += l+1;
  427. break;
  428. }
  429. memcpy ( c, &Response[Length], l+1 );
  430. Length += l+1;
  431. break;
  432. }
  433. case 'p':
  434. {
  435. char* c = va_arg ( Arguments, char* );
  436. byte l = 0;
  437. if (Length + 1 > ResponseLength)
  438. {
  439. Length++;
  440. break;
  441. }
  442. l = Response[Length++];
  443. if (Length + l > ResponseLength)
  444. {
  445. break;
  446. }
  447. memcpy ( c, &Response[Length], l );
  448. c[l+1] = 0;
  449. // Assumed to be final parameter, so Length not adjusted
  450. break;
  451. }
  452. case 'P':
  453. {
  454. PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING );
  455. OEM_STRING OemString;
  456. if (Length + 1 > ResponseLength)
  457. {
  458. Length++;
  459. break;
  460. }
  461. OemString.Length = Response[Length++];
  462. if (Length + OemString.Length > ResponseLength)
  463. {
  464. break;
  465. }
  466. OemString.Buffer = &Response[Length];
  467. //
  468. // Note the the Rtl function would set pUString->Buffer = NULL,
  469. // if OemString.Length is 0.
  470. //
  471. if ( OemString.Length != 0 ) {
  472. Status = RtlOemStringToCountedUnicodeString( pUString, &OemString, FALSE );
  473. if (!NT_SUCCESS( Status )) {
  474. pUString->Length = 0;
  475. NcpStatus = Status;
  476. }
  477. } else {
  478. pUString->Length = 0;
  479. }
  480. // Assumed to be final parameter, so Length not adjusted
  481. break;
  482. }
  483. case 'r':
  484. {
  485. byte* b = va_arg ( Arguments, byte* );
  486. word l = va_arg ( Arguments, word );
  487. TdiCopyLookaheadData( b, &Response[Length], l, 0);
  488. Length += l;
  489. break;
  490. }
  491. case 'R':
  492. {
  493. //
  494. // Interpret the buffer as an ASCIIZ string. Convert
  495. // it to unicode in the preallocated buffer.
  496. //
  497. PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING );
  498. OEM_STRING OemString;
  499. USHORT len = va_arg ( Arguments, USHORT );
  500. OemString.Buffer = &Response[Length];
  501. OemString.Length = 0;
  502. // make sure not to go past end of Response
  503. while ( OemString.Length + Length <= ResponseLength )
  504. {
  505. if ( Response[Length + OemString.Length] == 0 )
  506. break;
  507. OemString.Length++;
  508. }
  509. OemString.MaximumLength = OemString.Length;
  510. if (Length + OemString.Length > ResponseLength)
  511. {
  512. Length += len;
  513. break;
  514. }
  515. //
  516. // Note the the Rtl function would set pUString->Buffer = NULL,
  517. // if OemString.Length is 0.
  518. //
  519. if ( OemString.Length != 0) {
  520. Status = RtlOemStringToCountedUnicodeString( pUString, &OemString, FALSE );
  521. if (!NT_SUCCESS( Status )) {
  522. ASSERT( Status == STATUS_BUFFER_OVERFLOW );
  523. pUString->Length = 0;
  524. NcpStatus = Status;
  525. }
  526. } else {
  527. pUString->Length = 0;
  528. }
  529. Length += len;
  530. break;
  531. }
  532. case 'W':
  533. {
  534. WORD *w = va_arg ( Arguments, WORD* );
  535. if (Length + 2 > ResponseLength)
  536. {
  537. Length += 2;
  538. break;
  539. }
  540. *w = (* (WORD *)&Response[Length]);
  541. Length += 2;
  542. break;
  543. }
  544. case 'D':
  545. {
  546. DWORD *d = va_arg ( Arguments, DWORD* );
  547. if (Length + 4 > ResponseLength)
  548. {
  549. Length += 4;
  550. break;
  551. }
  552. *d = (* (DWORD *)&Response[Length]);
  553. Length += 4;
  554. break;
  555. }
  556. case 'S':
  557. {
  558. PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
  559. USHORT strl;
  560. if (pU) {
  561. if (Length + 4 > ResponseLength)
  562. {
  563. Length += 4;
  564. break;
  565. }
  566. strl = (USHORT)(* (DWORD *)&Response[Length]);
  567. //
  568. // Don't count the null terminator that is part of
  569. // Novell's counted unicode string.
  570. //
  571. pU->Length = strl - sizeof( WCHAR );
  572. Length += 4;
  573. if (Length + pU->Length <= ResponseLength)
  574. RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
  575. Length += ROUNDUP4(strl);
  576. } else {
  577. //
  578. // Skip over the string since we don't want it.
  579. //
  580. if (Length + 4 > ResponseLength)
  581. {
  582. Length += 4;
  583. break;
  584. }
  585. Length += ROUNDUP4((* (DWORD *)&Response[Length] ));
  586. Length += 4;
  587. }
  588. break;
  589. }
  590. case 's':
  591. {
  592. PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
  593. USHORT strl;
  594. if (pU) {
  595. if (Length + 4 > ResponseLength)
  596. {
  597. Length += 4;
  598. break;
  599. }
  600. strl = (USHORT)(* (DWORD *)&Response[Length]);
  601. pU->Length = strl;
  602. Length += 4;
  603. if (Length + pU->Length <= ResponseLength)
  604. RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
  605. Length += ROUNDUP4(strl);
  606. } else {
  607. //
  608. // Skip over the string since we don't want it.
  609. //
  610. if (Length + 4 > ResponseLength)
  611. {
  612. Length += 4;
  613. break;
  614. }
  615. Length += ROUNDUP4((* (DWORD *)&Response[Length] ));
  616. Length += 4;
  617. }
  618. break;
  619. }
  620. case 'T':
  621. {
  622. PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
  623. USHORT strl;
  624. if (pU) {
  625. if (Length + 4 > ResponseLength)
  626. {
  627. Length += 4;
  628. break;
  629. }
  630. strl = (USHORT)(* (DWORD *)&Response[Length] );
  631. strl -= sizeof( WCHAR ); // Don't count the NULL from NDS.
  632. if ( strl <= pU->MaximumLength ) {
  633. pU->Length = strl;
  634. Length += 4;
  635. if (Length + pU->Length <= ResponseLength)
  636. RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
  637. //
  638. // No need to advance the pointers since this is
  639. // specifically a termination case!
  640. //
  641. } else {
  642. pU->Length = 0;
  643. }
  644. }
  645. break;
  646. }
  647. case 't':
  648. {
  649. PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
  650. USHORT strl;
  651. if (pU) {
  652. if (Length + 4 > ResponseLength)
  653. {
  654. Length += 4;
  655. break;
  656. }
  657. strl = (USHORT)(* (DWORD *)&Response[Length] );
  658. if ( strl <= pU->MaximumLength ) {
  659. pU->Length = strl;
  660. Length += 4;
  661. if (Length + pU->Length <= ResponseLength)
  662. RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
  663. //
  664. // No need to advance the pointers since this is
  665. // specifically a termination case!
  666. //
  667. } else {
  668. pU->Length = 0;
  669. }
  670. }
  671. break;
  672. }
  673. /*
  674. case 's':
  675. {
  676. char *c = va_arg( Arguments, char * );
  677. WORD l = va_arg( Arguments, WORD );
  678. ULONG len = (* (DWORD *)&Response[Length]);
  679. Length += 4;
  680. // How to fix this?
  681. // l = WideCharToMultiByte(CP_ACP,0,(WCHAR *)&Response[Length],Length/2,c,l,0,0);
  682. // if (!l) {
  683. // #ifdef NWDBG
  684. // DbgPrint( "ParseResponse case s couldnt translate from WCHAR.\n" );
  685. // #endif
  686. // goto ErrorExit;
  687. // }
  688. len = ROUNDUP4(len);
  689. Length += len;
  690. break;
  691. }
  692. case 'V':
  693. {
  694. BYTE **b = va_arg( Arguments, BYTE **);
  695. DWORD *pLen = va_arg ( Arguments, DWORD *);
  696. DWORD len = (* (DWORD *)&Response[Length]);
  697. Length += 4;
  698. if (b) {
  699. *b = (BYTE *)&Response[Length];
  700. }
  701. if (pLen) {
  702. *pLen = len;
  703. }
  704. Length += ROUNDUP4(len);
  705. break;
  706. }
  707. case 'l':
  708. {
  709. BYTE* b = va_arg ( Arguments, BYTE* );
  710. BYTE* w = va_arg ( Arguments, BYTE* );
  711. WORD i;
  712. b[1] = Response[Length++];
  713. b[0] = Response[Length++];
  714. for ( i = 0; i < ((WORD) *b); i++, w += sizeof(WORD) )
  715. {
  716. w[1] = Response[Length++];
  717. w[0] = Response[Length++];
  718. }
  719. break;
  720. }
  721. */
  722. #ifdef NWDBG
  723. default:
  724. DbgPrintf ( "*****exchange: invalid response field, %x\n", *FormatByte );
  725. DbgBreakPoint();
  726. #endif
  727. }
  728. if ( Length > ResponseLength ) {
  729. #ifdef NWDBG
  730. DbgPrintf ( "*****exchange: not enough response data, %d\n", Length );
  731. if ( IrpContext ) {
  732. Error( EVENT_NWRDR_INVALID_REPLY,
  733. STATUS_UNEXPECTED_NETWORK_ERROR,
  734. NULL,
  735. 0,
  736. 1,
  737. IrpContext->pNpScb->ServerName.Buffer );
  738. }
  739. #endif
  740. return( STATUS_UNEXPECTED_NETWORK_ERROR );
  741. }
  742. FormatByte++;
  743. }
  744. va_end( Arguments );
  745. return( NcpStatus );
  746. }
  747. NTSTATUS
  748. ParseNcpResponse(
  749. PIRP_CONTEXT IrpContext,
  750. PNCP_RESPONSE Response
  751. )
  752. {
  753. NTSTATUS Status;
  754. if ( Response->Status == 0 ) {
  755. Status = NwErrorToNtStatus( Response->Error );
  756. } else {
  757. Status = NwConnectionStatusToNtStatus( Response->Status );
  758. if ( Status == STATUS_REMOTE_DISCONNECT ) {
  759. Stats.ServerDisconnects++;
  760. IrpContext->pNpScb->State = SCB_STATE_RECONNECT_REQUIRED;
  761. }
  762. }
  763. return( Status );
  764. }
  765. NTSTATUS
  766. FormatRequest(
  767. PIRP_CONTEXT pIrpC,
  768. PEX pEx,
  769. char* f,
  770. va_list a // format specific parameters
  771. )
  772. /*++
  773. Routine Description:
  774. Send the packet described by f and the additional parameters. When a
  775. valid response has been received call pEx with the resonse.
  776. An exchange is a generic way of assembling a request packet of a
  777. given type, containing a set of fields, sending the packet, receiving
  778. a response packet, and disassembling the fields of the response packet.
  779. The packet type and each field is specified by individual
  780. characters in a format string.
  781. The exchange procedure takes such a format string plus additional
  782. parameters as necessary for each character in the string as specified
  783. below.
  784. Arguments: '']
  785. pIrpC - supplies the irp context for the exchange request.
  786. pEx - supplies the routine to process the data.
  787. f... - supplies the information needed to create the request to the
  788. server. The first byte indicates the packet type and the
  789. following bytes contain field types.
  790. Packet types:
  791. 'A' SAP broadcast ( void )
  792. 'B' NCP burst ( dword, dword, byte )
  793. 'C' NCP connect ( void )
  794. 'F' NCP function ( byte )
  795. 'S' NCP subfunction ( byte, byte )
  796. 'N' NCP subfunction w/o size ( byte, byte )
  797. 'D' NCP disconnect ( void )
  798. 'E' Echo data ( void )
  799. Field types, request/response:
  800. 'b' byte ( byte / byte* )
  801. 'w' hi-lo word ( word / word* )
  802. 'd' hi-lo dword ( dword / dword* )
  803. 'W' lo-hi word ( word / word* )
  804. 'D' lo-hi dword ( dword / dword* )
  805. '-' zero/skip byte ( void )
  806. '=' zero/skip word ( void )
  807. ._. zero/skip string ( word )
  808. 'p' pstring ( char* )
  809. 'u' p unicode string ( UNICODE_STRING * )
  810. 'U' p uppercase string( UNICODE_STRING * )
  811. 'J' variant of U ( UNICODE_STRING * )
  812. 'c' cstring ( char* )
  813. 'v' cstring ( UNICODE_STRING* )
  814. 'r' raw bytes ( byte*, word )
  815. 'w' fixed length unicode ( UNICODE_STRING*, word )
  816. 'C' Component format name, with count ( UNICODE_STRING * )
  817. 'N' Component format name, no count ( UNICODE_STRING * )
  818. 'f' separate fragment ( PMDL )
  819. An 'f' field must be last, and in a response it cannot be
  820. preceeded by 'p' or 'c' fields.
  821. Return Value:
  822. Normally returns STATUS_SUCCESS.
  823. --*/
  824. {
  825. NTSTATUS status;
  826. char* z;
  827. word data_size;
  828. PNONPAGED_SCB pNpScb = pIrpC->pNpScb;
  829. dword dwData;
  830. ASSERT( pIrpC->NodeTypeCode == NW_NTC_IRP_CONTEXT );
  831. ASSERT( pIrpC->pNpScb != NULL );
  832. status= STATUS_LINK_FAILED;
  833. pIrpC->pEx = pEx; // Routine to process reply
  834. pIrpC->Destination = pNpScb->RemoteAddress;
  835. ClearFlag( pIrpC->Flags, IRP_FLAG_SEQUENCE_NO_REQUIRED );
  836. switch ( *f ) {
  837. case 'A':
  838. // Send to local network (0), a broadcast (-1), socket 0x452
  839. pIrpC->Destination = SapBroadcastAddress;
  840. pIrpC->PacketType = SAP_BROADCAST;
  841. data_size = 0;
  842. pNpScb->RetryCount = 3;
  843. pNpScb->MaxTimeOut = 2 * pNpScb->TickCount + 10;
  844. pNpScb->TimeOut = pNpScb->MaxTimeOut;
  845. SetFlag( pIrpC->Flags, IRP_FLAG_RETRY_SEND );
  846. break;
  847. case 'E':
  848. pIrpC->Destination = pNpScb->EchoAddress;
  849. pIrpC->PacketType = NCP_ECHO;
  850. //
  851. // For echo packets use a short timeout and a small retry count.
  852. // Set the retry send bit, so that SendNow doesn't reset the
  853. // RetryCount to a bigger number. If we start getting packets
  854. // after we've timed out, we'll increase the wait time.
  855. //
  856. pNpScb->RetryCount = 0;
  857. pNpScb->MaxTimeOut = 2 * pNpScb->TickCount + 7 + pNpScb->LipTickAdjustment;
  858. pNpScb->TimeOut = pNpScb->MaxTimeOut;
  859. SetFlag( pIrpC->Flags, IRP_FLAG_RETRY_SEND );
  860. SetFlag( pIrpC->Flags, IRP_FLAG_REROUTE_ATTEMPTED );
  861. data_size = 0;
  862. break;
  863. case 'C':
  864. pIrpC->PacketType = NCP_CONNECT;
  865. *(PUSHORT)&pIrpC->req[0] = PEP_COMMAND_CONNECT;
  866. pIrpC->req[2] = 0x00;
  867. pIrpC->req[3] = 0xFF;
  868. pIrpC->req[4] = 0x00;
  869. pIrpC->req[5] = 0xFF;
  870. data_size = 6;
  871. pNpScb->MaxTimeOut = 16 * pNpScb->TickCount + 10;
  872. pNpScb->TimeOut = 4 * pNpScb->TickCount + 10;
  873. pNpScb->SequenceNo = 0;
  874. break;
  875. case 'F':
  876. pIrpC->PacketType = NCP_FUNCTION;
  877. goto FallThrough;
  878. case 'S':
  879. case 'N':
  880. pIrpC->PacketType = NCP_SUBFUNCTION;
  881. goto FallThrough;
  882. case 'L':
  883. pIrpC->PacketType = NCP_SUBFUNCTION;
  884. goto FallThrough;
  885. case 'D':
  886. pIrpC->PacketType = NCP_DISCONNECT;
  887. FallThrough:
  888. if ( *f == 'D' ) {
  889. *(PUSHORT)&pIrpC->req[0] = PEP_COMMAND_DISCONNECT;
  890. } else {
  891. *(PUSHORT)&pIrpC->req[0] = PEP_COMMAND_REQUEST;
  892. }
  893. pNpScb->RetryCount = DefaultRetryCount ;
  894. pNpScb->MaxTimeOut = 2 * pNpScb->TickCount + 10;
  895. pNpScb->TimeOut = pNpScb->SendTimeout;
  896. //
  897. // Mark this packet as SequenceNumberRequired. We need to guarantee
  898. // the packets are sent in sequence number order, so we will
  899. // fill in the sequence number when we are ready to send the
  900. // packet.
  901. //
  902. SetFlag( pIrpC->Flags, IRP_FLAG_SEQUENCE_NO_REQUIRED );
  903. pIrpC->req[3] = pNpScb->ConnectionNo;
  904. pIrpC->req[5] = pNpScb->ConnectionNoHigh;
  905. if ( pIrpC->Icb != NULL && pIrpC->Icb->Pid != INVALID_PID ) {
  906. pIrpC->req[4] = (UCHAR)pIrpC->Icb->Pid;
  907. } else {
  908. pIrpC->req[4] = 0xFF;
  909. }
  910. data_size = 6;
  911. if ( *f == 'L' ) {
  912. pIrpC->req[data_size++] = NCP_LFN_FUNCTION;
  913. }
  914. if ( *f != 'D' ) {
  915. pIrpC->req[data_size++] = va_arg( a, byte );
  916. }
  917. if ( *f == 'S' ) {
  918. data_size += 2;
  919. pIrpC->req[data_size++] = va_arg( a, byte );
  920. }
  921. if ( *f == 'N' ) {
  922. pIrpC->req[data_size++] = va_arg( a, byte );
  923. }
  924. break;
  925. case 'B':
  926. pIrpC->PacketType = NCP_BURST;
  927. *(PUSHORT)&pIrpC->req[0] = PEP_COMMAND_BURST;
  928. pNpScb->TimeOut = pNpScb->MaxTimeOut;
  929. //
  930. // tommye - MS bug 2743 changed the RetryCount from 20 to be based off the
  931. // default retry count, nudged up a little.
  932. //
  933. if ( !BooleanFlagOn( pIrpC->Flags, IRP_FLAG_RETRY_SEND ) ) {
  934. pNpScb->RetryCount = DefaultRetryCount * 2;
  935. }
  936. pIrpC->req[3] = 0x2; // Stream Type = Big Send Burst
  937. *(PULONG)&pIrpC->req[4] = pNpScb->SourceConnectionId;
  938. *(PULONG)&pIrpC->req[8] = pNpScb->DestinationConnectionId;
  939. LongByteSwap( (*(PULONG)&pIrpC->req[16]) , pNpScb->CurrentBurstDelay ); // Send delay time
  940. dwData = va_arg( a, dword ); // Size of data
  941. LongByteSwap( pIrpC->req[24], dwData );
  942. dwData = va_arg( a, dword ); // Offset of data
  943. LongByteSwap( pIrpC->req[28], dwData );
  944. pIrpC->req[2] = va_arg( a, byte ); // Burst flags
  945. data_size = 34;
  946. break;
  947. default:
  948. DbgPrintf ( "*****exchange: invalid packet type, %x\n", *f );
  949. DbgBreakPoint();
  950. va_end( a );
  951. return status;
  952. }
  953. z = f;
  954. while ( *++z && *z != 'f' )
  955. {
  956. switch ( *z )
  957. {
  958. case '=':
  959. pIrpC->req[data_size++] = 0;
  960. case '-':
  961. pIrpC->req[data_size++] = 0;
  962. break;
  963. case '_':
  964. {
  965. word l = va_arg ( a, word );
  966. ASSERT( data_size + l <= MAX_SEND_DATA );
  967. while ( l-- )
  968. pIrpC->req[data_size++] = 0;
  969. break;
  970. }
  971. case 's':
  972. {
  973. word l = va_arg ( a, word );
  974. ASSERT ( data_size + l <= MAX_SEND_DATA );
  975. data_size += l;
  976. break;
  977. }
  978. case 'i':
  979. pIrpC->req[4] = va_arg ( a, byte );
  980. break;
  981. case 'b':
  982. pIrpC->req[data_size++] = va_arg ( a, byte );
  983. break;
  984. case 'w':
  985. {
  986. word w = va_arg ( a, word );
  987. pIrpC->req[data_size++] = (byte) (w >> 8);
  988. pIrpC->req[data_size++] = (byte) (w >> 0);
  989. break;
  990. }
  991. case 'd':
  992. {
  993. dword d = va_arg ( a, dword );
  994. pIrpC->req[data_size++] = (byte) (d >> 24);
  995. pIrpC->req[data_size++] = (byte) (d >> 16);
  996. pIrpC->req[data_size++] = (byte) (d >> 8);
  997. pIrpC->req[data_size++] = (byte) (d >> 0);
  998. break;
  999. }
  1000. case 'W':
  1001. {
  1002. word w = va_arg ( a, word );
  1003. *(word UNALIGNED *)&pIrpC->req[data_size] = w;
  1004. data_size += 2;
  1005. break;
  1006. }
  1007. case 'D':
  1008. {
  1009. dword d = va_arg ( a, dword );
  1010. *(dword UNALIGNED *)&pIrpC->req[data_size] = d;
  1011. data_size += 4;
  1012. break;
  1013. }
  1014. case 'c':
  1015. {
  1016. char* c = va_arg ( a, char* );
  1017. word l = (word)strlen( c );
  1018. ASSERT (data_size + l <= MAX_SEND_DATA );
  1019. RtlCopyMemory( &pIrpC->req[data_size], c, l+1 );
  1020. data_size += l + 1;
  1021. break;
  1022. }
  1023. case 'v':
  1024. {
  1025. PUNICODE_STRING pUString = va_arg ( a, PUNICODE_STRING );
  1026. OEM_STRING OemString;
  1027. ULONG Length;
  1028. Length = RtlUnicodeStringToOemSize( pUString ) - 1;
  1029. ASSERT (( data_size + Length <= MAX_SEND_DATA) && ( (Length & 0xffffff00) == 0) );
  1030. OemString.Buffer = &pIrpC->req[data_size];
  1031. OemString.MaximumLength = (USHORT)Length + 1;
  1032. status = RtlUnicodeStringToCountedOemString( &OemString, pUString, FALSE );
  1033. ASSERT( NT_SUCCESS( status ));
  1034. data_size += (USHORT)Length + 1;
  1035. break;
  1036. }
  1037. case 'p':
  1038. {
  1039. char* c = va_arg ( a, char* );
  1040. byte l = (byte)strlen( c );
  1041. if ((data_size+l>MAX_SEND_DATA) ||
  1042. ( (l & 0xffffff00) != 0) ) {
  1043. ASSERT("***exchange: Packet too long!2!\n" && FALSE );
  1044. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  1045. }
  1046. pIrpC->req[data_size++] = l;
  1047. RtlCopyMemory( &pIrpC->req[data_size], c, l );
  1048. data_size += l;
  1049. break;
  1050. }
  1051. case 'J':
  1052. case 'U':
  1053. case 'u':
  1054. {
  1055. PUNICODE_STRING pUString = va_arg ( a, PUNICODE_STRING );
  1056. OEM_STRING OemString;
  1057. PUCHAR pOemString;
  1058. ULONG Length;
  1059. ULONG i;
  1060. //
  1061. // Calculate required string length, excluding trailing NUL.
  1062. //
  1063. Length = RtlUnicodeStringToOemSize( pUString ) - 1;
  1064. ASSERT( Length < 0x100 );
  1065. if (( data_size + Length > MAX_SEND_DATA ) ||
  1066. ( (Length & 0xffffff00) != 0) ) {
  1067. ASSERT("***exchange:Packet too long or name >255 chars!4!\n" && FALSE);
  1068. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  1069. }
  1070. pIrpC->req[data_size++] = (UCHAR)Length;
  1071. OemString.Buffer = &pIrpC->req[data_size];
  1072. OemString.MaximumLength = (USHORT)Length + 1;
  1073. if ( *z == 'u' ) {
  1074. status = RtlUnicodeStringToCountedOemString(
  1075. &OemString,
  1076. pUString,
  1077. FALSE );
  1078. } else {
  1079. status = RtlUpcaseUnicodeStringToCountedOemString(
  1080. &OemString,
  1081. pUString,
  1082. FALSE );
  1083. }
  1084. if ( !NT_SUCCESS( status ) ) {
  1085. return status;
  1086. }
  1087. data_size += (USHORT)Length;
  1088. if (( Japan ) &&
  1089. ( *z == 'J' )) {
  1090. //
  1091. // Netware Japanese version The following single byte character is replaced with another one
  1092. // if the string is for File Name only when sending from Client to Server.
  1093. //
  1094. // U+0xFF7F SJIS+0xBF -> 0x10
  1095. // U+0xFF6E SJIS+0xAE -> 0x11
  1096. // U+0xFF64 SJIS+0xAA -> 0x12
  1097. //
  1098. for ( i = 0 , pOemString = OemString.Buffer ; i < Length ; i++ , pOemString++ ) {
  1099. //
  1100. // In fact Novell server seems to convert all 0xBF, 0xAA, 0xAE
  1101. // and 0x5C even if they are DBCS lead or trail byte.
  1102. // We can't single out DBCS case in the conversion.
  1103. //
  1104. if( FsRtlIsLeadDbcsCharacter( *pOemString ) ) {
  1105. if(*pOemString == 0xBF ) {
  1106. *pOemString = 0x10;
  1107. }else if(*pOemString == 0xAE ) {
  1108. *pOemString = 0x11;
  1109. }else if(*pOemString == 0xAA ) {
  1110. *pOemString = 0x12;
  1111. }
  1112. // Trail byte
  1113. i++; pOemString++;
  1114. if(*pOemString == 0x5C ) {
  1115. //
  1116. // The trailbyte is 0x5C, replace it with 0x13
  1117. //
  1118. *pOemString = 0x13;
  1119. }
  1120. //
  1121. // Continue to check other conversions for trailbyte.
  1122. //
  1123. }
  1124. if ( *pOemString == 0xBF ) {
  1125. *pOemString = 0x10;
  1126. } else if ( *pOemString == 0xAA ) {
  1127. *pOemString = 0x12;
  1128. } else if ( *pOemString == 0xAE ) {
  1129. *pOemString = 0x11;
  1130. }
  1131. }
  1132. }
  1133. break;
  1134. }
  1135. case 'r':
  1136. {
  1137. byte* b = va_arg ( a, byte* );
  1138. word l = va_arg ( a, word );
  1139. if (data_size+l>MAX_SEND_DATA) {
  1140. ASSERT("***exchange: Packet too long!6!\n"&& FALSE);
  1141. return STATUS_UNSUCCESSFUL;
  1142. }
  1143. RtlCopyMemory( &pIrpC->req[data_size], b, l );
  1144. data_size += l;
  1145. break;
  1146. }
  1147. case 'x':
  1148. {
  1149. PUNICODE_STRING pUString = va_arg ( a, PUNICODE_STRING );
  1150. ULONG RequiredLength = va_arg( a, word );
  1151. ULONG Length;
  1152. OEM_STRING OemString;
  1153. //
  1154. // Convert this string to an OEM string.
  1155. //
  1156. status = RtlUnicodeStringToCountedOemString( &OemString, pUString, TRUE );
  1157. ASSERT( NT_SUCCESS( status ));
  1158. if (!NT_SUCCESS(status)) {
  1159. return status;
  1160. }
  1161. if ( data_size + RequiredLength > MAX_SEND_DATA ) {
  1162. ASSERT("***exchange: Packet too long!4!\n" && FALSE);
  1163. return STATUS_UNSUCCESSFUL;
  1164. }
  1165. //
  1166. // Copy the oem string to the buffer, padded with 0's if
  1167. // necessary.
  1168. //
  1169. Length = MIN( OemString.Length, RequiredLength );
  1170. RtlMoveMemory( &pIrpC->req[data_size], OemString.Buffer, Length );
  1171. if ( RequiredLength > Length ) {
  1172. RtlFillMemory(
  1173. &pIrpC->req[data_size+Length],
  1174. RequiredLength - Length,
  1175. 0 );
  1176. }
  1177. RtlFreeAnsiString(&OemString);
  1178. data_size += (USHORT)RequiredLength;
  1179. break;
  1180. }
  1181. case 'C':
  1182. case 'N':
  1183. {
  1184. PUNICODE_STRING pUString = va_arg ( a, PUNICODE_STRING );
  1185. OEM_STRING OemString;
  1186. PWCH thisChar, lastChar, firstChar;
  1187. PCHAR componentCountPtr, pchar;
  1188. CHAR componentCount;
  1189. UNICODE_STRING UnicodeString;
  1190. int i;
  1191. //
  1192. // Copy the oem string to the buffer, in component format.
  1193. //
  1194. thisChar = pUString->Buffer;
  1195. lastChar = &pUString->Buffer[ pUString->Length / sizeof(WCHAR) ];
  1196. //
  1197. // Skip leading path separators
  1198. //
  1199. while ( (thisChar < lastChar) &&
  1200. (*thisChar == OBJ_NAME_PATH_SEPARATOR)) {
  1201. thisChar++;
  1202. }
  1203. componentCount = 0;
  1204. if ( *z == 'C' ) {
  1205. componentCountPtr = &pIrpC->req[data_size++];
  1206. }
  1207. while ( thisChar < lastChar ) {
  1208. if ( data_size >= MAX_SEND_DATA - 1 ) {
  1209. ASSERT( ("***exchange: Packet too long or name > 255 chars!5!\n" && FALSE) );
  1210. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  1211. }
  1212. firstChar = thisChar;
  1213. while ( thisChar < lastChar &&
  1214. *thisChar != OBJ_NAME_PATH_SEPARATOR ) {
  1215. thisChar++;
  1216. }
  1217. ++componentCount;
  1218. UnicodeString.Buffer = firstChar;
  1219. UnicodeString.Length = (USHORT) (( thisChar - firstChar ) * sizeof(WCHAR));
  1220. OemString.Buffer = &pIrpC->req[data_size + 1];
  1221. OemString.MaximumLength = MAX_SEND_DATA - data_size - 1;
  1222. status = RtlUnicodeStringToCountedOemString( &OemString, &UnicodeString, FALSE );
  1223. pIrpC->req[data_size] = (UCHAR)OemString.Length;
  1224. data_size += OemString.Length + 1;
  1225. if ( !NT_SUCCESS( status ) || data_size > MAX_SEND_DATA ) {
  1226. // ASSERT("***exchange: Packet too long or name > 255 chars!5!\n" && FALSE );
  1227. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  1228. }
  1229. //
  1230. // Search the result OEM string for the character 0xFF.
  1231. // If it's there, fail this request. The server doesn't
  1232. // deal with 0xFF very well.
  1233. //
  1234. for ( pchar = OemString.Buffer, i = 0;
  1235. i < OemString.Length;
  1236. pchar++, i++ ) {
  1237. //
  1238. // We need to check for dbcs, because 0xff is a
  1239. // legal trail byte for EUDC characters.
  1240. //
  1241. if ( FsRtlIsLeadDbcsCharacter( (UCHAR)*pchar ) ) {
  1242. //
  1243. // Skip dbcs character.
  1244. //
  1245. pchar++; i++;
  1246. continue;
  1247. }
  1248. if (( (UCHAR)*pchar == LFN_META_CHARACTER ) ||
  1249. !FsRtlIsAnsiCharacterLegalHpfs(*pchar, FALSE) ) {
  1250. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  1251. }
  1252. }
  1253. thisChar++; // Skip the path separator
  1254. }
  1255. if ( *z == 'C' ) {
  1256. *componentCountPtr = componentCount;
  1257. }
  1258. break;
  1259. }
  1260. default:
  1261. #ifdef NWDBG
  1262. DbgPrintf ( "*****exchange: invalid request field, %x\n", *z );
  1263. DbgBreakPoint();
  1264. #endif
  1265. ;
  1266. }
  1267. if ( data_size > MAX_SEND_DATA )
  1268. {
  1269. DbgPrintf( "*****exchange: CORRUPT, too much request data\n" );
  1270. DbgBreakPoint();
  1271. va_end( a );
  1272. return STATUS_UNSUCCESSFUL;
  1273. }
  1274. }
  1275. pIrpC->TxMdl->ByteCount = data_size;
  1276. if ( *z == 'f' )
  1277. {
  1278. PMDL mdl;
  1279. //
  1280. // Fragment of data following Ipx header. Next parameter is
  1281. // the address of the mdl describing the fragment.
  1282. //
  1283. ++z;
  1284. mdl = (PMDL) va_arg ( a, byte* );
  1285. pIrpC->TxMdl->Next = mdl;
  1286. data_size += (USHORT)MdlLength( mdl );
  1287. }
  1288. if ( *f == 'S' ) {
  1289. pIrpC->req[7] = (data_size-9) >> 8;
  1290. pIrpC->req[8] = (data_size-9);
  1291. } else if ( *f == 'B' ) {
  1292. //
  1293. // For burst packets set the number of bytes in this packet to
  1294. // a real number for burst requests, and to 0 for a missing packet
  1295. // request.
  1296. //
  1297. if ( *(PUSHORT)&pIrpC->req[34] == 0 ) {
  1298. USHORT RealDataSize = data_size - 36;
  1299. ShortByteSwap( pIrpC->req[32], RealDataSize );
  1300. } else {
  1301. *(PUSHORT)&pIrpC->req[32] = 0;
  1302. }
  1303. }
  1304. va_end( a );
  1305. return( STATUS_SUCCESS );
  1306. }
  1307. NTSTATUS
  1308. PrepareAndSendPacket(
  1309. PIRP_CONTEXT pIrpContext
  1310. )
  1311. {
  1312. PreparePacket( pIrpContext, pIrpContext->pOriginalIrp, pIrpContext->TxMdl );
  1313. return SendPacket( pIrpContext, pIrpContext->pNpScb );
  1314. }
  1315. VOID
  1316. PreparePacket(
  1317. PIRP_CONTEXT pIrpContext,
  1318. PIRP pIrp,
  1319. PMDL pMdl
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. This routine builds the IRP for sending a packet.
  1324. Arguments:
  1325. IrpContext - A pointer to IRP context information for the request
  1326. being processed.
  1327. Irp - The IRP to be used to submit the request to the transport.
  1328. Mdl - A pointer to the MDL for the data to send.
  1329. Return Value:
  1330. None.
  1331. --*/
  1332. {
  1333. PIO_COMPLETION_ROUTINE CompletionRoutine;
  1334. PNW_TDI_STRUCT pTdiStruct;
  1335. DebugTrace(0, Dbg, "PreparePacket...\n", 0);
  1336. pIrpContext->ConnectionInformation.UserDataLength = 0;
  1337. pIrpContext->ConnectionInformation.OptionsLength = sizeof( UCHAR );
  1338. pIrpContext->ConnectionInformation.Options =
  1339. (pIrpContext->PacketType == SAP_BROADCAST) ?
  1340. &SapPacketType : &NcpPacketType;
  1341. pIrpContext->ConnectionInformation.RemoteAddressLength = sizeof(TA_IPX_ADDRESS);
  1342. pIrpContext->ConnectionInformation.RemoteAddress = &pIrpContext->Destination;
  1343. #if NWDBG
  1344. dump( Dbg,
  1345. &pIrpContext->Destination.Address[0].Address[0],
  1346. sizeof(TDI_ADDRESS_IPX));
  1347. dumpMdl( Dbg, pMdl);
  1348. #endif
  1349. //
  1350. // Set the socket to use for this send. If unspecified in the
  1351. // IRP context, use the default (server) socket.
  1352. //
  1353. pTdiStruct = pIrpContext->pTdiStruct == NULL ?
  1354. &pIrpContext->pNpScb->Server : pIrpContext->pTdiStruct;
  1355. CompletionRoutine = pIrpContext->CompletionSendRoutine == NULL ?
  1356. CompletionSend : pIrpContext->CompletionSendRoutine;
  1357. TdiBuildSendDatagram(
  1358. pIrp,
  1359. pTdiStruct->pDeviceObject,
  1360. pTdiStruct->pFileObject,
  1361. CompletionRoutine,
  1362. pIrpContext,
  1363. pMdl,
  1364. MdlLength( pMdl ),
  1365. &pIrpContext->ConnectionInformation );
  1366. //
  1367. // Set the run routine to send now, only if this is the main IRP
  1368. // for this irp context.
  1369. //
  1370. if ( pIrp == pIrpContext->pOriginalIrp ) {
  1371. pIrpContext->RunRoutine = SendNow;
  1372. }
  1373. return;
  1374. }
  1375. NTSTATUS
  1376. SendPacket(
  1377. PIRP_CONTEXT pIrpC,
  1378. PNONPAGED_SCB pNpScb
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. Queue a packet created by exchange and try to send it to the server.
  1383. Arguments:
  1384. pIrpC - supplies the irp context for the request creating the socket.
  1385. pNpScb - supplies the server to receive the request.
  1386. Return Value:
  1387. STATUS_PENDING
  1388. --*/
  1389. {
  1390. if ( AppendToScbQueue( pIrpC, pNpScb ) ) {
  1391. KickQueue( pNpScb );
  1392. }
  1393. return STATUS_PENDING;
  1394. }
  1395. BOOLEAN
  1396. AppendToScbQueue(
  1397. PIRP_CONTEXT IrpContext,
  1398. PNONPAGED_SCB NpScb
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. Queue an IRP context to the SCB, if it is not already there.
  1403. Arguments:
  1404. IrpContext - Supplies the IRP context to queue.
  1405. NpScb - Supplies the server to receive the request.
  1406. Return Value:
  1407. TRUE - The IRP Context is at the front of the queue.
  1408. FALSE - The IRP Context is not at the front of the queue.
  1409. --*/
  1410. {
  1411. PLIST_ENTRY ListEntry;
  1412. #ifdef MSWDBG
  1413. KIRQL OldIrql;
  1414. #endif
  1415. DebugTrace(0, Dbg, "AppendToScbQueue... %08lx\n", NpScb);
  1416. DebugTrace(0, Dbg, "IrpContext = %08lx\n", IrpContext );
  1417. //
  1418. // Look at the IRP Context flags. If the IRP is already on the
  1419. // queue, then it must be at the front and ready for processing.
  1420. //
  1421. if ( FlagOn( IrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE ) ) {
  1422. ASSERT( NpScb->Requests.Flink == &IrpContext->NextRequest );
  1423. return( TRUE );
  1424. }
  1425. #ifdef MSWDBG
  1426. NpScb->RequestQueued = TRUE;
  1427. #endif
  1428. #if 0 // Resource layout changed on Daytona. Disable for now.
  1429. //
  1430. // Make sure that this thread isn't holding the RCB while waiting for
  1431. // the SCB queue.
  1432. //
  1433. ASSERT ( NwRcb.Resource.InitialOwnerThreads[0] != (ULONG)PsGetCurrentThread() );
  1434. #endif
  1435. //
  1436. // The IRP Context was not at the front. Queue it, then look to
  1437. // see if it was appended to an empty queue.
  1438. //
  1439. SetFlag( IrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  1440. #ifdef MSWDBG
  1441. ExAcquireSpinLock( &NpScb->NpScbSpinLock, &OldIrql );
  1442. if ( IsListEmpty( &NpScb->Requests ) ) {
  1443. ListEntry = NULL;
  1444. } else {
  1445. ListEntry = NpScb->Requests.Flink;
  1446. }
  1447. InsertTailList( &NpScb->Requests, &IrpContext->NextRequest );
  1448. IrpContext->SequenceNumber = NpScb->SequenceNumber++;
  1449. ExReleaseSpinLock( &NpScb->NpScbSpinLock, OldIrql );
  1450. #else
  1451. ListEntry = ExInterlockedInsertTailList(
  1452. &NpScb->Requests,
  1453. &IrpContext->NextRequest,
  1454. &NpScb->NpScbSpinLock );
  1455. #endif
  1456. if ( ListEntry == NULL ) {
  1457. ASSERT( NpScb->Requests.Flink == &IrpContext->NextRequest );
  1458. DebugTrace(-1, Dbg, "AppendToScbQueue -> TRUE\n", 0);
  1459. return( TRUE );
  1460. } else {
  1461. DebugTrace(-1, Dbg, "AppendToScbQueue -> FALSE\n", 0);
  1462. return( FALSE );
  1463. }
  1464. }
  1465. VOID
  1466. KickQueue(
  1467. PNONPAGED_SCB pNpScb
  1468. )
  1469. /*++
  1470. Routine Description:
  1471. Queue a packet created by exchange and try to send it to the server.
  1472. Note: NpScbSpinLock must be held before calling this routine.
  1473. Arguments:
  1474. pNpScb - supplies the server queue to kick into life.
  1475. Return Value:
  1476. none.
  1477. --*/
  1478. {
  1479. PIRP_CONTEXT pIrpC;
  1480. PRUN_ROUTINE RunRoutine;
  1481. KIRQL OldIrql;
  1482. DebugTrace( +1, Dbg, "KickQueue...%08lx\n", pNpScb);
  1483. KeAcquireSpinLock( &pNpScb->NpScbSpinLock, &OldIrql );
  1484. if ( IsListEmpty( &pNpScb->Requests )) {
  1485. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  1486. DebugTrace( -1, Dbg, " Empty Queue\n", 0);
  1487. return;
  1488. }
  1489. pIrpC = CONTAINING_RECORD(pNpScb->Requests.Flink, IRP_CONTEXT, NextRequest);
  1490. ASSERT( pIrpC->pNpScb->Requests.Flink == &pIrpC->NextRequest );
  1491. ASSERT( pIrpC->NodeTypeCode == NW_NTC_IRP_CONTEXT);
  1492. RunRoutine = pIrpC->RunRoutine;
  1493. // Only call the routine to tell it it is at the front once
  1494. pIrpC->RunRoutine = NULL;
  1495. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  1496. //
  1497. // If the redir is shutting down do not process this request
  1498. // unless we must.
  1499. //
  1500. if ( NwRcb.State != RCB_STATE_RUNNING &&
  1501. !FlagOn( pIrpC->Flags, IRP_FLAG_SEND_ALWAYS ) ) {
  1502. //
  1503. // Note that it's safe to call the pEx routine without the
  1504. // spin lock held since this IrpContext just made it to the
  1505. // front of the queue, and so can't have i/o in progress.
  1506. //
  1507. if ( pIrpC->pEx != NULL) {
  1508. pIrpC->pEx( pIrpC, 0, NULL );
  1509. DebugTrace( -1, Dbg, "KickQueue\n", 0);
  1510. return;
  1511. }
  1512. }
  1513. if ( RunRoutine != NULL ) {
  1514. ASSERT( pNpScb->Receiving == FALSE );
  1515. RunRoutine( pIrpC );
  1516. }
  1517. DebugTrace( -1, Dbg, "KickQueue\n", 0);
  1518. return;
  1519. }
  1520. VOID
  1521. SendNow(
  1522. PIRP_CONTEXT IrpContext
  1523. )
  1524. /*++
  1525. Routine Description:
  1526. This routine submits a TDI send request to the tranport layer.
  1527. Arguments:
  1528. IrpContext - A pointer to IRP context information for the request
  1529. being processed.
  1530. Return Value:
  1531. None.
  1532. --*/
  1533. {
  1534. PNONPAGED_SCB pNpScb;
  1535. NTSTATUS Status;
  1536. PIO_STACK_LOCATION IrpSp;
  1537. pNpScb = IrpContext->pNpScb;
  1538. if ( !BooleanFlagOn( IrpContext->Flags, IRP_FLAG_RETRY_SEND ) ) {
  1539. pNpScb->RetryCount = DefaultRetryCount;
  1540. }
  1541. //
  1542. // Ensure that this IRP Context is really at the front of the queue.
  1543. //
  1544. ASSERT( pNpScb->Requests.Flink == &IrpContext->NextRequest );
  1545. IrpContext->RunRoutine = NULL;
  1546. //
  1547. // Make sure that this is a correctly formatted send request.
  1548. //
  1549. IrpSp = IoGetNextIrpStackLocation( IrpContext->pOriginalIrp );
  1550. ASSERT( IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL );
  1551. ASSERT( IrpSp->MinorFunction == TDI_SEND_DATAGRAM );
  1552. //
  1553. // This IRP context has a packet ready to send. Send it now.
  1554. //
  1555. pNpScb->Sending = TRUE;
  1556. if ( !BooleanFlagOn( IrpContext->Flags, IRP_FLAG_NOT_OK_TO_RECEIVE ) ) {
  1557. pNpScb->OkToReceive = TRUE;
  1558. }
  1559. pNpScb->Receiving = FALSE;
  1560. pNpScb->Received = FALSE;
  1561. //
  1562. // If this packet requires a sequence number, set it now.
  1563. // The sequence number is updated when we receive a response.
  1564. //
  1565. // We do not need to synchronize access to SequenceNo since
  1566. // this is the only active packet for this SCB.
  1567. //
  1568. if ( BooleanFlagOn( IrpContext->Flags, IRP_FLAG_SEQUENCE_NO_REQUIRED ) ) {
  1569. ClearFlag( IrpContext->Flags, IRP_FLAG_SEQUENCE_NO_REQUIRED );
  1570. IrpContext->req[2] = pNpScb->SequenceNo;
  1571. }
  1572. //
  1573. // If this packet is a burst packet, fill in the burst sequence number
  1574. // now, and burst request number.
  1575. //
  1576. if ( BooleanFlagOn( IrpContext->Flags, IRP_FLAG_BURST_PACKET ) ) {
  1577. LongByteSwap( IrpContext->req[12], pNpScb->BurstSequenceNo );
  1578. pNpScb->BurstSequenceNo++;
  1579. ShortByteSwap( IrpContext->req[20], pNpScb->BurstRequestNo );
  1580. ShortByteSwap( IrpContext->req[22], pNpScb->BurstRequestNo );
  1581. }
  1582. DebugTrace( +0, Dbg, "Irp %X\n", IrpContext->pOriginalIrp);
  1583. DebugTrace( +0, Dbg, "pIrpC %X\n", IrpContext);
  1584. DebugTrace( +0, Dbg, "Mdl %X\n", IrpContext->TxMdl);
  1585. #if NWDBG
  1586. dumpMdl( Dbg, IrpContext->TxMdl);
  1587. #endif
  1588. {
  1589. ULONG len = 0;
  1590. PMDL Next = IrpContext->TxMdl;
  1591. do {
  1592. len += MmGetMdlByteCount(Next);
  1593. } while (Next = Next->Next);
  1594. Stats.BytesTransmitted.QuadPart += len;
  1595. }
  1596. Status = IoCallDriver(pNpScb->Server.pDeviceObject, IrpContext->pOriginalIrp);
  1597. DebugTrace( -1, Dbg, "Transport returned: %08lx\n", Status );
  1598. Stats.NcpsTransmitted.QuadPart++;
  1599. return;
  1600. }
  1601. VOID
  1602. SetEvent(
  1603. PIRP_CONTEXT IrpContext
  1604. )
  1605. /*++
  1606. Routine Description:
  1607. This routine set the IrpContext Event to the signalled state.
  1608. Arguments:
  1609. IrpContext - A pointer to IRP context information for the request
  1610. being processed.
  1611. Return Value:
  1612. None.
  1613. --*/
  1614. {
  1615. //
  1616. // Ensure that this IRP Context is really at the front of the queue.
  1617. //
  1618. ASSERT( IrpContext->pNpScb->Requests.Flink == &IrpContext->NextRequest );
  1619. //
  1620. // This IRP context has a thread waiting to get to the front of
  1621. // the queue. Set the event to indicate that it can continue.
  1622. //
  1623. #ifdef MSWDBG
  1624. ASSERT( IrpContext->Event.Header.SignalState == 0 );
  1625. IrpContext->DebugValue = 0x105;
  1626. #endif
  1627. DebugTrace( +0, Dbg, "Setting event for IrpContext %X\n", IrpContext );
  1628. NwSetIrpContextEvent( IrpContext );
  1629. }
  1630. USHORT
  1631. NextSocket(
  1632. IN USHORT OldValue
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. This routine returns the byteswapped OldValue++ wrapping from 7fff.
  1637. Arguments:
  1638. OldValue - supplies the existing socket number in the range
  1639. 0x4000 to 0x7fff.
  1640. Return Value:
  1641. USHORT OldValue++
  1642. --*/
  1643. {
  1644. USHORT TempValue = OldValue + 0x0100;
  1645. if ( TempValue < 0x100 ) {
  1646. if ( TempValue == 0x007f ) {
  1647. // Wrap back to 0x4000 from 0xff7f
  1648. return 0x0040;
  1649. } else {
  1650. // Go from something like 0xff40 to 0x0041
  1651. return TempValue + 1;
  1652. }
  1653. }
  1654. return TempValue;
  1655. }
  1656. ULONG
  1657. MdlLength (
  1658. register IN PMDL Mdl
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. This routine returns the number of bytes in an MDL.
  1663. Arguments:
  1664. IN PMDL Mdl - Supplies the MDL to determine the length on.
  1665. Return Value:
  1666. ULONG - Number of bytes in the MDL
  1667. --*/
  1668. {
  1669. register ULONG Size = 0;
  1670. while (Mdl!=NULL) {
  1671. Size += MmGetMdlByteCount(Mdl);
  1672. Mdl = Mdl->Next;
  1673. }
  1674. return Size;
  1675. }
  1676. NTSTATUS
  1677. CompletionSend(
  1678. IN PDEVICE_OBJECT DeviceObject,
  1679. IN PIRP Irp,
  1680. IN PVOID Context
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. This routine does not complete the Irp. It is used to signal to a
  1685. synchronous part of the driver that it can proceed.
  1686. Arguments:
  1687. DeviceObject - unused.
  1688. Irp - Supplies Irp that the transport has finished processing.
  1689. Context - Supplies the IrpContext associated with the Irp.
  1690. Return Value:
  1691. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  1692. processing Irp stack locations at this point.
  1693. --*/
  1694. {
  1695. PNONPAGED_SCB pNpScb;
  1696. PIRP_CONTEXT pIrpC = (PIRP_CONTEXT) Context;
  1697. KIRQL OldIrql;
  1698. //
  1699. // Avoid completing the Irp because the Mdl etc. do not contain
  1700. // their original values.
  1701. //
  1702. DebugTrace( +1, Dbg, "CompletionSend\n", 0);
  1703. DebugTrace( +0, Dbg, "Irp %X\n", Irp);
  1704. DebugTrace( +0, Dbg, "pIrpC %X\n", pIrpC);
  1705. DebugTrace( +0, Dbg, "Status %X\n", Irp->IoStatus.Status);
  1706. pNpScb = pIrpC->pNpScb;
  1707. KeAcquireSpinLock( &pNpScb->NpScbSpinLock, &OldIrql );
  1708. ASSERT( pNpScb->Sending == TRUE );
  1709. pNpScb->Sending = FALSE;
  1710. //
  1711. // If we got a receive indication while waiting for send
  1712. // completion and the data is all valid, call the receive handler routine now.
  1713. //
  1714. if ( pNpScb->Received ) {
  1715. pNpScb->Receiving = FALSE;
  1716. pNpScb->Received = FALSE;
  1717. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  1718. pIrpC->pEx(
  1719. pIrpC,
  1720. pIrpC->ResponseLength,
  1721. pIrpC->rsp );
  1722. } else if (( Irp->IoStatus.Status == STATUS_DEVICE_DOES_NOT_EXIST ) ||
  1723. ( Irp->IoStatus.Status == STATUS_BAD_NETWORK_PATH ) ||
  1724. ( Irp->IoStatus.Status == STATUS_INVALID_BUFFER_SIZE ) ||
  1725. ( Irp->IoStatus.Status == STATUS_NETWORK_UNREACHABLE )) {
  1726. //
  1727. // The send failed.
  1728. //
  1729. //
  1730. // If this SCB is still flagged okay to receive (how could it not?)
  1731. // simply call the callback routine to indicate failure.
  1732. //
  1733. // If the SendCompletion hasn't happened, set up so that send
  1734. // completion will call the callback routine.
  1735. //
  1736. if ( pNpScb->OkToReceive ) {
  1737. pNpScb->OkToReceive = FALSE;
  1738. ClearFlag( pIrpC->Flags, IRP_FLAG_RETRY_SEND );
  1739. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  1740. DebugTrace(+0, Dbg, "Send failed\n", 0 );
  1741. pIrpC->ResponseParameters.Error = ERROR_UNEXP_NET_ERR;
  1742. pIrpC->pEx( pIrpC, 0, NULL );
  1743. } else {
  1744. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  1745. }
  1746. } else {
  1747. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  1748. }
  1749. DebugTrace( -1, Dbg, "CompletionSend STATUS_MORE_PROCESSING_REQUIRED\n", 0);
  1750. return STATUS_MORE_PROCESSING_REQUIRED;
  1751. UNREFERENCED_PARAMETER( DeviceObject );
  1752. UNREFERENCED_PARAMETER( Irp );
  1753. }
  1754. #if NWDBG
  1755. BOOLEAN UseIrpReceive = FALSE;
  1756. #endif
  1757. NTSTATUS
  1758. ServerDatagramHandler(
  1759. IN PVOID TdiEventContext,
  1760. IN int SourceAddressLength,
  1761. IN PVOID SourceAddress,
  1762. IN int OptionsLength,
  1763. IN PVOID Options,
  1764. IN ULONG ReceiveDatagramFlags,
  1765. IN ULONG BytesIndicated,
  1766. IN ULONG BytesAvailable,
  1767. OUT ULONG *BytesTaken,
  1768. IN PVOID Tsdu,
  1769. OUT PIRP *IoRequestPacket
  1770. )
  1771. /*++
  1772. Routine Description:
  1773. This routine is the receive datagram event indication handler for the
  1774. Server socket.
  1775. Arguments:
  1776. TdiEventContext - Context provided for this event, a pointer to the
  1777. non paged SCB.
  1778. SourceAddressLength - Length of the originator of the datagram.
  1779. SourceAddress - String describing the originator of the datagram.
  1780. OptionsLength - Length of the buffer pointed to by Options.
  1781. Options - Options for the receive.
  1782. ReceiveDatagramFlags - Ignored.
  1783. BytesIndicated - Number of bytes this indication.
  1784. BytesAvailable - Number of bytes in complete Tsdu.
  1785. BytesTaken - Returns the number of bytes used.
  1786. Tsdu - Pointer describing this TSDU, typically a lump of bytes.
  1787. IoRequestPacket - TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  1788. Return Value:
  1789. NTSTATUS - Status of receive operation
  1790. --*/
  1791. {
  1792. PNONPAGED_SCB pNpScb = (PNONPAGED_SCB)TdiEventContext;
  1793. NTSTATUS Status = STATUS_DATA_NOT_ACCEPTED;
  1794. UCHAR PacketType;
  1795. PUCHAR RspData = (PUCHAR)Tsdu;
  1796. PIRP_CONTEXT pIrpC;
  1797. PNW_TDI_STRUCT pTdiStruct;
  1798. BOOLEAN AcceptPacket = TRUE;
  1799. PNCP_BURST_READ_RESPONSE pBurstRsp;
  1800. NTSTATUS BurstStatus;
  1801. *IoRequestPacket = NULL;
  1802. #if DBG
  1803. pTdiStruct = NULL;
  1804. #endif
  1805. if (pNpScb->NodeTypeCode != NW_NTC_SCBNP ) {
  1806. DebugTrace(+0, 0, "nwrdr: Invalid Server Indication %x\n", pNpScb );
  1807. #if DBG
  1808. DbgBreakPoint();
  1809. #endif
  1810. return STATUS_DATA_NOT_ACCEPTED;
  1811. }
  1812. #if NWDBG
  1813. // Debug only trick to test IRP receive.
  1814. if ( UseIrpReceive ) {
  1815. BytesIndicated = 0;
  1816. }
  1817. #endif
  1818. DebugTrace(+1, Dbg, "ServerDatagramHandler\n", 0);
  1819. DebugTrace(+0, Dbg, "Server %x\n", pNpScb);
  1820. DebugTrace(+0, Dbg, "BytesIndicated %x\n", BytesIndicated);
  1821. DebugTrace(+0, Dbg, "BytesAvailable %x\n", BytesAvailable);
  1822. //
  1823. // SourceAddress is the address of the server or the bridge tbat sent
  1824. // the packet.
  1825. //
  1826. #if NWDBG
  1827. dump( Dbg, SourceAddress, SourceAddressLength );
  1828. dump( Dbg, Tsdu, BytesIndicated );
  1829. #endif
  1830. if ( OptionsLength == 1 ) {
  1831. PacketType = *(PCHAR)Options;
  1832. DebugTrace(+0, Dbg, "PacketType %x\n", PacketType);
  1833. } else {
  1834. DebugTrace(+0, Dbg, "OptionsLength %x\n", OptionsLength);
  1835. #if NWDBG
  1836. dump( Dbg, Options, OptionsLength );
  1837. #endif
  1838. }
  1839. KeAcquireSpinLockAtDpcLevel(&pNpScb->NpScbSpinLock );
  1840. if ( !pNpScb->OkToReceive ) {
  1841. //
  1842. // This SCB is not expecting to receive any data.
  1843. // Discard this packet.
  1844. //
  1845. DropCount++;
  1846. DebugTrace(+0, Dbg, "OkToReceive == FALSE - discard packet\n", 0);
  1847. AcceptPacket = FALSE;
  1848. goto process_packet;
  1849. }
  1850. pIrpC = CONTAINING_RECORD(pNpScb->Requests.Flink, IRP_CONTEXT, NextRequest);
  1851. ASSERT( pIrpC->NodeTypeCode == NW_NTC_IRP_CONTEXT);
  1852. //
  1853. // Verify that this packet came from where we expect it to come from,
  1854. // and that is has a minimum size.
  1855. //
  1856. if ( ( pIrpC->PacketType != SAP_BROADCAST &&
  1857. RtlCompareMemory(
  1858. &pIrpC->Destination,
  1859. SourceAddress,
  1860. SourceAddressLength ) != (ULONG)SourceAddressLength ) ||
  1861. BytesIndicated < 8 ) {
  1862. AcceptPacket = FALSE;
  1863. #ifdef NWDBG
  1864. DbgPrintf ( "***exchange: stray response tossed\n", 0 );
  1865. #endif
  1866. goto process_packet;
  1867. }
  1868. switch ( pIrpC->PacketType ) {
  1869. case SAP_BROADCAST:
  1870. //
  1871. // We are expected a SAP Broadcast frame. Ensure that this
  1872. // is a correctly formatted SAP.
  1873. //
  1874. if ( pIrpC->req[0] != RspData[0] ||
  1875. pIrpC->req[2] != RspData[2] ||
  1876. pIrpC->req[3] != RspData[3] ||
  1877. SourceAddressLength != sizeof(TA_IPX_ADDRESS) ) {
  1878. DbgPrintf ( "***exchange: bad SAP packet\n" );
  1879. AcceptPacket = FALSE;
  1880. }
  1881. pTdiStruct = &pNpScb->Server;
  1882. break;
  1883. case NCP_BURST:
  1884. if ( *(USHORT UNALIGNED *)&RspData[0] == PEP_COMMAND_BURST ) {
  1885. if ( BytesIndicated < 36 ) {
  1886. AcceptPacket = FALSE;
  1887. } else if ( ( RspData[2] & BURST_FLAG_SYSTEM_PACKET ) &&
  1888. RspData[34] == 0 &&
  1889. RspData[35] == 0 ) {
  1890. //
  1891. // We have burst mode busy reponse.
  1892. //
  1893. DebugTrace(+0, Dbg, "Burst mode busy\n", 0 );
  1894. NwProcessPositiveAck( pNpScb );
  1895. AcceptPacket = FALSE;
  1896. } else {
  1897. USHORT Brn;
  1898. //
  1899. // Check the burst sequence number.
  1900. //
  1901. ShortByteSwap( Brn, RspData[20] );
  1902. if ( pNpScb->BurstRequestNo == Brn ) {
  1903. pTdiStruct = &pNpScb->Burst;
  1904. AcceptPacket = TRUE;
  1905. } else {
  1906. AcceptPacket = FALSE;
  1907. }
  1908. }
  1909. } else {
  1910. AcceptPacket = FALSE;
  1911. }
  1912. break;
  1913. case NCP_ECHO:
  1914. //
  1915. // If this is the LIP packet that we are expecting, then accept it.
  1916. // However, on a slow link, it could be an old LIP packet that we
  1917. // have already given up on. If this is the case, we should drop
  1918. // the packet and increase the LIP max wait time.
  1919. //
  1920. // The sequence number is the fourth DWORD in the response and the
  1921. // maximum LIP tick adjustment that we will allow is 18 ticks, which
  1922. // is 1 second.
  1923. //
  1924. pTdiStruct = &pNpScb->Echo;
  1925. if ( *(DWORD UNALIGNED *)&RspData[12] != pNpScb->LipSequenceNumber ) {
  1926. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "LIP packet received out of order.\n", 0 );
  1927. if ( pNpScb->LipTickAdjustment < 18 ) {
  1928. pNpScb->LipTickAdjustment += 2;
  1929. }
  1930. AcceptPacket = FALSE;
  1931. } else {
  1932. AcceptPacket = TRUE;
  1933. }
  1934. break;
  1935. default:
  1936. pTdiStruct = &pNpScb->Server;
  1937. //
  1938. // This is the handling for all packets types other than
  1939. // SAP Broadcasts.
  1940. //
  1941. ASSERT( (pIrpC->PacketType == NCP_CONNECT) ||
  1942. (pIrpC->PacketType == NCP_FUNCTION) ||
  1943. (pIrpC->PacketType == NCP_SUBFUNCTION) ||
  1944. (pIrpC->PacketType == NCP_DISCONNECT));
  1945. if ( *(USHORT UNALIGNED *)&RspData[0] == PEP_COMMAND_ACKNOWLEDGE ) {
  1946. AcceptPacket = FALSE;
  1947. if ( RspData[2] == pIrpC->req[2] &&
  1948. RspData[3] == pIrpC->req[3] ) {
  1949. //
  1950. // We have received an ACK frame.
  1951. //
  1952. DebugTrace(+0, Dbg, "Received positive acknowledge\n", 0 );
  1953. NwProcessPositiveAck( pNpScb );
  1954. }
  1955. break;
  1956. } else if ( *(USHORT UNALIGNED *)&RspData[0] == PEP_COMMAND_BURST ) {
  1957. //
  1958. // This is a stray burst response, ignore it.
  1959. //
  1960. AcceptPacket = FALSE;
  1961. break;
  1962. } else if ( *(USHORT UNALIGNED *)&RspData[0] != PEP_COMMAND_RESPONSE ) {
  1963. //
  1964. // We have received an invalid frame.
  1965. //
  1966. DbgPrintf ( "***exchange: invalid Response\n" );
  1967. AcceptPacket = FALSE;
  1968. break;
  1969. } else if ( pIrpC->PacketType == NCP_CONNECT ) {
  1970. pNpScb->SequenceNo = RspData[2];
  1971. pNpScb->ConnectionNo = RspData[3];
  1972. pNpScb->ConnectionNoHigh = RspData[5];
  1973. // We should now continue to process the Connect
  1974. break;
  1975. }
  1976. //
  1977. // Make sure this the response we expect.
  1978. //
  1979. if ( !VerifyResponse( pIrpC, RspData ) ) {
  1980. //
  1981. // This is a stray or corrupt response. Ignore it.
  1982. //
  1983. AcceptPacket = FALSE;
  1984. break;
  1985. } else {
  1986. //
  1987. // We have received a valid, in sequence response.
  1988. // Bump the current sequence number.
  1989. //
  1990. ++pNpScb->SequenceNo;
  1991. }
  1992. if ( pIrpC->PacketType == NCP_FUNCTION ||
  1993. pIrpC->PacketType == NCP_SUBFUNCTION ) {
  1994. if ( ( RspData[7] &
  1995. ( NCP_STATUS_BAD_CONNECTION |
  1996. NCP_STATUS_NO_CONNECTIONS ) ) != 0 ) {
  1997. //
  1998. // We've lost our connection to the server.
  1999. // Try to reconnect if it is allowed for this request.
  2000. //
  2001. pNpScb->State = SCB_STATE_RECONNECT_REQUIRED;
  2002. if ( BooleanFlagOn( pIrpC->Flags, IRP_FLAG_RECONNECTABLE ) ) {
  2003. ClearFlag( pIrpC->Flags, IRP_FLAG_RECONNECTABLE );
  2004. AcceptPacket = FALSE;
  2005. if (!pNpScb->Sending) {
  2006. ScheduleReconnectRetry( pIrpC );
  2007. pNpScb->OkToReceive = FALSE;
  2008. } else {
  2009. //
  2010. // If we are sending, it is not OK schedule the
  2011. // retry now, because if we do and the send
  2012. // completion hasnt been run we could end up
  2013. // with 2 guys thinking they are at the front
  2014. // of the queue. We let the send complete and
  2015. // wait for that to fail instead. We will
  2016. // eventually reconnect.
  2017. //
  2018. }
  2019. }
  2020. break;
  2021. } else if ( ( RspData[7] & NCP_STATUS_SHUTDOWN ) != 0 ) {
  2022. //
  2023. // This server's going down. We need to process this
  2024. // message in the FSP. Copy the indicated data and
  2025. // process in the FSP.
  2026. //
  2027. pNpScb->State = SCB_STATE_ATTACHING;
  2028. AcceptPacket = FALSE;
  2029. pNpScb->OkToReceive = FALSE;
  2030. pNpScb->Receiving = TRUE;
  2031. CopyIndicatedData(
  2032. pIrpC,
  2033. RspData,
  2034. BytesIndicated,
  2035. BytesTaken,
  2036. ReceiveDatagramFlags );
  2037. pIrpC->PostProcessRoutine = FspProcessServerDown;
  2038. Status = NwPostToFsp( pIrpC, FALSE );
  2039. break;
  2040. }
  2041. } else if ( pIrpC->PacketType == NCP_DISCONNECT ) {
  2042. //
  2043. // We have received a disconnect frame.
  2044. //
  2045. break;
  2046. }
  2047. }
  2048. process_packet:
  2049. if ( AcceptPacket ) {
  2050. ASSERT ( !IsListEmpty( &pNpScb->Requests ));
  2051. ASSERT( pIrpC->pEx != NULL );
  2052. //
  2053. // If we received this packet without a retry, adjust the
  2054. // send timeout value.
  2055. //
  2056. if (( !BooleanFlagOn( pIrpC->Flags, IRP_FLAG_RETRY_SEND ) ) &&
  2057. ( pIrpC->PacketType != NCP_BURST )) {
  2058. SHORT NewTimeout;
  2059. NewTimeout = ( pNpScb->SendTimeout + pNpScb->TickCount ) / 2;
  2060. //
  2061. // tommye - MS bug 10511 - added code to set pNpScb->TimeOut
  2062. // to sames as pNpScb->SendTimeout per bug report recommendation.
  2063. //
  2064. pNpScb->TimeOut = pNpScb->SendTimeout = MAX( NewTimeout, pNpScb->TickCount + 1 );
  2065. DebugTrace( 0, Dbg, "Successful exchange, new send timeout = %d\n", pNpScb->SendTimeout );
  2066. }
  2067. //
  2068. // If the transport didn't indicate all of the data, we'll need
  2069. // to post a receive IRP.
  2070. //
  2071. #ifdef NWDBG
  2072. if (( BytesIndicated < BytesAvailable ) ||
  2073. ( AlwaysAllocateIrp )){
  2074. #else
  2075. if ( BytesIndicated < BytesAvailable ) {
  2076. #endif
  2077. if ( ( BooleanFlagOn( pIrpC->Flags, IRP_FLAG_BURST_REQUEST ) ) &&
  2078. ( IsListEmpty( &pIrpC->Specific.Read.PacketList ) ) ) {
  2079. pBurstRsp = (PNCP_BURST_READ_RESPONSE)RspData;
  2080. BurstStatus = NwBurstResultToNtStatus( pBurstRsp->Result );
  2081. //
  2082. // If this entire burst failed with an error, we can't
  2083. // let the receive data routine signal the caller until
  2084. // the pEx gets called and we exit on the correct paths.
  2085. //
  2086. if ( !NT_SUCCESS( BurstStatus ) ) {
  2087. DebugTrace( 0, Dbg, "Special burst termination %08lx.\n", BurstStatus );
  2088. pIrpC->Specific.Read.Status = BurstStatus;
  2089. if ( pNpScb->Sending ) {
  2090. //
  2091. // If the send hasn't completed yet, we can't accept
  2092. // the packet because IPX may not have completed back
  2093. // to us yet!
  2094. //
  2095. KeReleaseSpinLockFromDpcLevel(&pNpScb->NpScbSpinLock );
  2096. DebugTrace(-1, Dbg, "ServerDatagramHandler -> STATUS_DATA_NOT_ACCEPTED (%08lx)\n", BurstStatus );
  2097. return( STATUS_DATA_NOT_ACCEPTED );
  2098. } else {
  2099. //
  2100. // Handle this one just like normal, except that we
  2101. // know it's going to fail in the receive data routine
  2102. // and we don't want the timeout routine to fire
  2103. // causing us all sort of grief, so we set OkToReceive
  2104. // to FALSE.
  2105. //
  2106. pNpScb->OkToReceive = FALSE;
  2107. }
  2108. }
  2109. }
  2110. FreeReceiveIrp( pIrpC ); // Free old Irp if one was allocated
  2111. Status = AllocateReceiveIrp(
  2112. pIrpC,
  2113. RspData,
  2114. BytesAvailable,
  2115. BytesTaken,
  2116. pTdiStruct );
  2117. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  2118. pNpScb->OkToReceive = FALSE;
  2119. pNpScb->Receiving = TRUE;
  2120. } else if (!NT_SUCCESS( Status ) ) {
  2121. pIrpC->ReceiveIrp = NULL;
  2122. Status = STATUS_INSUFFICIENT_RESOURCES;
  2123. }
  2124. KeReleaseSpinLockFromDpcLevel(&pNpScb->NpScbSpinLock );
  2125. *IoRequestPacket = pIrpC->ReceiveIrp;
  2126. } else {
  2127. pNpScb->OkToReceive = FALSE;
  2128. //
  2129. // The transport has indicated all of the data.
  2130. // If the send has completed, call the pEx routine,
  2131. // otherwise copy the data to a buffer and let the
  2132. // send completion routine call the pEx routine.
  2133. //
  2134. if ( pNpScb->Sending ) {
  2135. DebugTrace( 0, Dbg, "Received data before send completion\n", 0 );
  2136. Status = CopyIndicatedData(
  2137. pIrpC,
  2138. RspData,
  2139. BytesIndicated,
  2140. BytesTaken,
  2141. ReceiveDatagramFlags );
  2142. if (NT_SUCCESS(Status)) {
  2143. pNpScb->Received = TRUE;
  2144. pNpScb->Receiving = TRUE;
  2145. } else {
  2146. // Ignore this packet
  2147. pNpScb->OkToReceive = TRUE;
  2148. }
  2149. KeReleaseSpinLockFromDpcLevel(&pNpScb->NpScbSpinLock );
  2150. } else {
  2151. pNpScb->Receiving = FALSE;
  2152. pNpScb->Received = FALSE;
  2153. KeReleaseSpinLockFromDpcLevel(&pNpScb->NpScbSpinLock );
  2154. DebugTrace(+0, Dbg, "Call pIrpC->pEx %x\n", pIrpC->pEx );
  2155. Status = pIrpC->pEx(pIrpC,
  2156. BytesAvailable,
  2157. RspData);
  2158. }
  2159. *BytesTaken = BytesAvailable;
  2160. }
  2161. } else { //(!AcceptPacket)
  2162. KeReleaseSpinLockFromDpcLevel(&pNpScb->NpScbSpinLock );
  2163. Status = STATUS_DATA_NOT_ACCEPTED;
  2164. }
  2165. Stats.NcpsReceived.QuadPart++;
  2166. Stats.BytesReceived.QuadPart += BytesAvailable;
  2167. DebugTrace(-1, Dbg, "ServerDatagramHandler -> %08lx\n", Status );
  2168. return( Status );
  2169. } // ServerDatagramHandler
  2170. NTSTATUS
  2171. CopyIndicatedData(
  2172. PIRP_CONTEXT pIrpContext,
  2173. PCHAR ReceiveData,
  2174. ULONG BytesIndicated,
  2175. PULONG BytesAccepted,
  2176. ULONG ReceiveDatagramFlags
  2177. )
  2178. /*++
  2179. Routine Description:
  2180. This routine copies indicated data to a buffer. If the packet is small
  2181. enough the data is copied to the preallocated receive buffer in the
  2182. IRP context. If the packet is too long, a new buffer is allocated.
  2183. Arguments:
  2184. pIrpContext - A pointer the block of context information for the request
  2185. in progress.
  2186. ReceiveData - A pointer to the indicated data.
  2187. BytesIndicated - The number of bytes available in the received packet.
  2188. BytesAccepted - Returns the number of bytes accepted by the receive
  2189. routine.
  2190. ReceiveDatagramFlags - Receive flags given to us by the transport.
  2191. Return Value:
  2192. NTSTATUS - Status of receive operation
  2193. --*/
  2194. {
  2195. NTSTATUS Status;
  2196. PMDL ReceiveMdl;
  2197. PVOID MappedVa;
  2198. ULONG BytesToCopy;
  2199. BOOLEAN DeleteMdl = FALSE;
  2200. pIrpContext->ResponseLength = BytesIndicated;
  2201. //
  2202. // If there is a receive data routine, use it to generate the receive
  2203. // MDL, otherwise use the default MDL.
  2204. //
  2205. if ( pIrpContext->ReceiveDataRoutine != NULL ) {
  2206. Status = pIrpContext->ReceiveDataRoutine(
  2207. pIrpContext,
  2208. BytesIndicated,
  2209. BytesAccepted,
  2210. ReceiveData,
  2211. &ReceiveMdl );
  2212. if ( !NT_SUCCESS( Status ) ) {
  2213. return( Status );
  2214. }
  2215. //
  2216. // We can accept up to the size of a burst read header, plus
  2217. // 3 bytes of fluff for the unaligned read case.
  2218. //
  2219. ASSERT( *BytesAccepted <= sizeof(NCP_BURST_READ_RESPONSE) + 3 );
  2220. BytesIndicated -= *BytesAccepted;
  2221. ReceiveData += *BytesAccepted;
  2222. DeleteMdl = TRUE;
  2223. } else {
  2224. *BytesAccepted = 0;
  2225. ReceiveMdl = pIrpContext->RxMdl;
  2226. }
  2227. if ( ReceiveMdl != NULL ) {
  2228. while ( BytesIndicated > 0 && ReceiveMdl != NULL ) {
  2229. MappedVa = MmGetSystemAddressForMdlSafe( ReceiveMdl, NormalPagePriority );
  2230. BytesToCopy = MIN( MmGetMdlByteCount( ReceiveMdl ), BytesIndicated );
  2231. TdiCopyLookaheadData( MappedVa, ReceiveData, BytesToCopy, ReceiveDatagramFlags );
  2232. ReceiveMdl = ReceiveMdl->Next;
  2233. BytesIndicated -= BytesToCopy;
  2234. ReceiveData += BytesToCopy;
  2235. ASSERT( !( BytesIndicated != 0 && ReceiveMdl == NULL ) );
  2236. }
  2237. if (DeleteMdl) {
  2238. PMDL Mdl = pIrpContext->Specific.Read.PartialMdl;
  2239. PMDL NextMdl;
  2240. while ( Mdl != NULL ) {
  2241. NextMdl = Mdl->Next;
  2242. DebugTrace( 0, Dbg, "Freeing MDL %x\n", Mdl );
  2243. FREE_MDL( Mdl );
  2244. Mdl = NextMdl;
  2245. }
  2246. pIrpContext->Specific.Read.PartialMdl = NULL;
  2247. }
  2248. }
  2249. return( STATUS_SUCCESS );
  2250. }
  2251. NTSTATUS
  2252. AllocateReceiveIrp(
  2253. PIRP_CONTEXT pIrpContext,
  2254. PVOID ReceiveData,
  2255. ULONG BytesAvailable,
  2256. PULONG BytesAccepted,
  2257. PNW_TDI_STRUCT pTdiStruct
  2258. )
  2259. /*++
  2260. Routine Description:
  2261. This routine allocates an IRP and if necessary a receive buffer. It
  2262. then builds an MDL for the buffer and formats the IRP to do a TDI
  2263. receive.
  2264. Arguments:
  2265. pIrpContext - A pointer the block of context information for the request
  2266. in progress.
  2267. ReceiveData - The indicated data.
  2268. BytesAvailable - The number of bytes available in the received packet.
  2269. BytesAccepted - Returns the number of bytes accepted from the packet.
  2270. pTdiStruct - A pointer to the TdiStruct which has indicated the receive.
  2271. Return Value:
  2272. NTSTATUS - Status of receive operation
  2273. STATUS_MORE_PROCESSING_REQUIRED means we were successful.
  2274. --*/
  2275. {
  2276. PIRP Irp = NULL;
  2277. NTSTATUS Status = STATUS_SUCCESS;
  2278. ASSERT( pTdiStruct != NULL );
  2279. Irp = ALLOCATE_IRP( pIrpContext->pNpScb->Server.pDeviceObject->StackSize, FALSE );
  2280. if ( Irp == NULL ) {
  2281. Status = STATUS_INSUFFICIENT_RESOURCES;
  2282. goto CleanExit;
  2283. }
  2284. //
  2285. // If there is no receive data routine for this IRP, the
  2286. // RxMdl must point to a valid place to put the data.
  2287. //
  2288. // If there is a ReceiveDataRoutine it will build an MDL
  2289. //
  2290. if ( pIrpContext->ReceiveDataRoutine == NULL ) {
  2291. ULONG LengthOfMdl;
  2292. LengthOfMdl = MdlLength( pIrpContext->RxMdl );
  2293. //
  2294. // If the server sent more data than we can receive, simply
  2295. // ignore the excess. In particular 3.11 pads long name
  2296. // response with an excess of junk.
  2297. //
  2298. if ( BytesAvailable > LengthOfMdl ) {
  2299. BytesAvailable = LengthOfMdl;
  2300. }
  2301. Irp->MdlAddress = pIrpContext->RxMdl;
  2302. *BytesAccepted = 0;
  2303. } else {
  2304. Status = pIrpContext->ReceiveDataRoutine(
  2305. pIrpContext,
  2306. BytesAvailable,
  2307. BytesAccepted,
  2308. ReceiveData,
  2309. &Irp->MdlAddress );
  2310. if ( !NT_SUCCESS( Status ) ||
  2311. Irp->MdlAddress == NULL ) {
  2312. Status = STATUS_INSUFFICIENT_RESOURCES;
  2313. goto CleanExit;
  2314. }
  2315. SetFlag( pIrpContext->Flags, IRP_FLAG_FREE_RECEIVE_MDL );
  2316. }
  2317. CleanExit:
  2318. if ( !NT_SUCCESS( Status ) ) {
  2319. if ( Irp != NULL ) {
  2320. FREE_IRP( Irp );
  2321. }
  2322. Irp = NULL;
  2323. pIrpContext->ReceiveIrp = NULL;
  2324. Status = STATUS_DATA_NOT_ACCEPTED;
  2325. return( Status );
  2326. }
  2327. pIrpContext->ReceiveIrp = Irp;
  2328. Status = STATUS_MORE_PROCESSING_REQUIRED;
  2329. pIrpContext->ResponseLength = BytesAvailable;
  2330. TdiBuildReceive(
  2331. Irp,
  2332. pTdiStruct->pDeviceObject,
  2333. pTdiStruct->pFileObject,
  2334. ReceiveIrpCompletion,
  2335. pIrpContext,
  2336. Irp->MdlAddress,
  2337. 0,
  2338. BytesAvailable - *BytesAccepted );
  2339. IoSetNextIrpStackLocation( Irp );
  2340. return( Status );
  2341. }
  2342. NTSTATUS
  2343. ReceiveIrpCompletion(
  2344. PDEVICE_OBJECT DeviceObject,
  2345. PIRP Irp,
  2346. PVOID Context
  2347. )
  2348. /*++
  2349. Routine Description:
  2350. This routine is called when a recieve IRP completes.
  2351. Arguments:
  2352. DeviceObject - Unused.
  2353. Irp - The IRP that completed.
  2354. Context - A pointer the block of context information for the request
  2355. in progress.
  2356. Return Value:
  2357. NTSTATUS - Status of receive operation
  2358. --*/
  2359. {
  2360. PIRP_CONTEXT IrpContext = (PIRP_CONTEXT)Context;
  2361. PIO_STACK_LOCATION IrpSp;
  2362. PNONPAGED_SCB pNpScb;
  2363. PMDL Mdl, NextMdl;
  2364. KIRQL OldIrql;
  2365. ASSERT( Irp == IrpContext->ReceiveIrp );
  2366. pNpScb = IrpContext->pNpScb;
  2367. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2368. //
  2369. // Free the IRP MDL if we allocated one specifically for this IRP.
  2370. //
  2371. if ( BooleanFlagOn( IrpContext->Flags, IRP_FLAG_FREE_RECEIVE_MDL ) ) {
  2372. Mdl = IrpContext->Specific.Read.PartialMdl;
  2373. IrpContext->Specific.Read.PartialMdl = NULL;
  2374. while ( Mdl != NULL ) {
  2375. NextMdl = Mdl->Next;
  2376. DebugTrace( 0, Dbg, "Freeing MDL %x\n", Mdl );
  2377. FREE_MDL( Mdl );
  2378. Mdl = NextMdl;
  2379. }
  2380. }
  2381. if ( !NT_SUCCESS( Irp->IoStatus.Status ) ) {
  2382. //
  2383. // Failed to receive the data. Wait for more.
  2384. //
  2385. pNpScb->OkToReceive = TRUE;
  2386. return STATUS_MORE_PROCESSING_REQUIRED;
  2387. }
  2388. //
  2389. // If the send has completed, call the pEx routine,
  2390. // otherwise copy the data to a buffer and let the
  2391. // send completion routine call the pEx routine.
  2392. //
  2393. KeAcquireSpinLock( &pNpScb->NpScbSpinLock, &OldIrql );
  2394. if ( pNpScb->Sending ) {
  2395. DebugTrace( 0, Dbg, "Received data before send completion\n", 0 );
  2396. //
  2397. // Tell send completion to call pEx.
  2398. //
  2399. pNpScb->Received = TRUE;
  2400. KeReleaseSpinLock(&pNpScb->NpScbSpinLock, OldIrql );
  2401. } else {
  2402. pNpScb->Receiving = FALSE;
  2403. pNpScb->Received = FALSE;
  2404. KeReleaseSpinLock( &pNpScb->NpScbSpinLock, OldIrql );
  2405. DebugTrace(+0, Dbg, "Call pIrpC->pEx %x\n", IrpContext->pEx );
  2406. IrpContext->pEx(
  2407. IrpContext,
  2408. IrpContext->ResponseLength,
  2409. IrpContext->rsp );
  2410. }
  2411. return STATUS_MORE_PROCESSING_REQUIRED;
  2412. }
  2413. VOID
  2414. FreeReceiveIrp(
  2415. PIRP_CONTEXT IrpContext
  2416. )
  2417. /*++
  2418. Routine Description:
  2419. This routine frees a IRP that was allocated to do a receive.
  2420. Arguments:
  2421. IrpContext - A pointer the block of context information for the request
  2422. in progress.
  2423. Return Value:
  2424. NTSTATUS - Status of receive operation
  2425. --*/
  2426. {
  2427. if ( IrpContext->ReceiveIrp == NULL ) {
  2428. return;
  2429. }
  2430. FREE_IRP( IrpContext->ReceiveIrp );
  2431. IrpContext->ReceiveIrp = NULL;
  2432. }
  2433. NTSTATUS
  2434. WatchDogDatagramHandler(
  2435. IN PVOID TdiEventContext,
  2436. IN int SourceAddressLength,
  2437. IN PVOID SourceAddress,
  2438. IN int OptionsLength,
  2439. IN PVOID Options,
  2440. IN ULONG ReceiveDatagramFlags,
  2441. IN ULONG BytesIndicated,
  2442. IN ULONG BytesAvailable,
  2443. OUT ULONG *BytesTaken,
  2444. IN PVOID Tsdu,
  2445. OUT PIRP *IoRequestPacket
  2446. )
  2447. /*++
  2448. Routine Description:
  2449. This routine is the receive datagram event indication handler for the
  2450. Server socket.
  2451. Arguments:
  2452. TdiEventContext - Context provided for this event, a pointer to the
  2453. non paged SCB.
  2454. SourceAddressLength - Length of the originator of the datagram.
  2455. SourceAddress - String describing the originator of the datagram.
  2456. OptionsLength - Length of the buffer pointed to by Options.
  2457. Options - Options for the receive.
  2458. ReceiveDatagramFlags - Ignored.
  2459. BytesIndicated - Number of bytes this indication.
  2460. BytesAvailable - Number of bytes in complete Tsdu.
  2461. BytesTaken - Returns the number of bytes used.
  2462. Tsdu - Pointer describing this TSDU, typically a lump of bytes.
  2463. IoRequestPacket - TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  2464. Return Value:
  2465. NTSTATUS - Status of receive operation
  2466. --*/
  2467. {
  2468. PNONPAGED_SCB pNpScb = (PNONPAGED_SCB)TdiEventContext;
  2469. PUCHAR RspData = (PUCHAR)Tsdu;
  2470. *IoRequestPacket = NULL;
  2471. //
  2472. // Transport will complete the processing of the request, we don't
  2473. // want the datagram.
  2474. //
  2475. DebugTrace(+1, Dbg, "WatchDogDatagramHandler\n", 0);
  2476. DebugTrace(+0, Dbg, "SourceAddressLength %x\n", SourceAddressLength);
  2477. DebugTrace(+0, Dbg, "BytesIndicated %x\n", BytesIndicated);
  2478. DebugTrace(+0, Dbg, "BytesAvailable %x\n", BytesAvailable);
  2479. DebugTrace(+0, Dbg, "BytesTaken %x\n", *BytesTaken);
  2480. //
  2481. // SourceAddress is the address of the server or the bridge tbat sent
  2482. // the packet.
  2483. //
  2484. #if NWDBG
  2485. dump( Dbg, SourceAddress, SourceAddressLength );
  2486. dump( Dbg, Tsdu, BytesIndicated );
  2487. #endif
  2488. if (pNpScb->NodeTypeCode != NW_NTC_SCBNP ) {
  2489. DebugTrace(+0, 0, "nwrdr: Invalid Watchdog Indication %x\n", pNpScb );
  2490. #if DBG
  2491. DbgBreakPoint();
  2492. #endif
  2493. return STATUS_DATA_NOT_ACCEPTED;
  2494. }
  2495. Stats.NcpsReceived.QuadPart++;
  2496. Stats.BytesReceived.QuadPart += BytesAvailable;
  2497. if ( RspData[1] == NCP_SEARCH_CONTINUE ) {
  2498. PIRP pIrp;
  2499. PIRP_CONTEXT pIrpContext;
  2500. pIrp = ALLOCATE_IRP( pNpScb->WatchDog.pDeviceObject->StackSize, FALSE);
  2501. if (pIrp == NULL) {
  2502. DebugTrace(-1, Dbg, " %lx\n", STATUS_DATA_NOT_ACCEPTED);
  2503. return STATUS_DATA_NOT_ACCEPTED;
  2504. }
  2505. try {
  2506. pIrpContext = AllocateIrpContext( pIrp );
  2507. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2508. FREE_IRP( pIrp );
  2509. DebugTrace(-1, Dbg, " %lx\n", STATUS_DATA_NOT_ACCEPTED);
  2510. return STATUS_DATA_NOT_ACCEPTED;
  2511. }
  2512. pIrpContext->req[0] = pNpScb->ConnectionNo;
  2513. //
  2514. // Response 'Y' or connection is valid and its from the right server,
  2515. // or 'N' if it is not.
  2516. //
  2517. if (( RspData[0] == pNpScb->ConnectionNo ) &&
  2518. ( RtlCompareMemory(
  2519. ((PTA_IPX_ADDRESS)SourceAddress)->Address[0].Address,
  2520. &pNpScb->ServerAddress,
  2521. 8) == 8 ))
  2522. {
  2523. LARGE_INTEGER KillTime, Now;
  2524. BOOL ScbIsOld ;
  2525. //
  2526. // Check if this is a not-logged-in SCB that has not been used
  2527. // for while. If it is, answer NO. In attach.c, we dont disconnect
  2528. // from a nearest server immediately to avoid the re-connect
  2529. // overheads. This is where we time it out.
  2530. //
  2531. KeQuerySystemTime( &Now );
  2532. KillTime.QuadPart = Now.QuadPart - ( NwOneSecond * DORMANT_SCB_KEEP_TIME);
  2533. ScbIsOld = ((pNpScb->State == SCB_STATE_LOGIN_REQUIRED) &&
  2534. (pNpScb->LastUsedTime.QuadPart < KillTime.QuadPart)) ;
  2535. pIrpContext->req[1] = ScbIsOld ? 'N' : 'Y';
  2536. if (ScbIsOld)
  2537. {
  2538. pNpScb->State = SCB_STATE_RECONNECT_REQUIRED ;
  2539. //
  2540. //---- Multi-user code merge ----
  2541. //
  2542. Stats.Sessions--;
  2543. if ( pNpScb->MajorVersion == 2 ) {
  2544. Stats.NW2xConnects--;
  2545. } else if ( pNpScb->MajorVersion == 3 ) {
  2546. Stats.NW3xConnects--;
  2547. } else if ( pNpScb->MajorVersion == 4 ) {
  2548. Stats.NW4xConnects--;
  2549. }
  2550. //---------------------------------
  2551. }
  2552. DebugTrace(-1,Dbg,"WatchDog Response: %s\n", ScbIsOld ? "N" : "Y");
  2553. } else {
  2554. pIrpContext->req[1] = 'N';
  2555. }
  2556. pIrpContext->TxMdl->ByteCount = 2;
  2557. pIrpContext->ConnectionInformation.UserDataLength = 0;
  2558. pIrpContext->ConnectionInformation.OptionsLength = sizeof( UCHAR );
  2559. pIrpContext->ConnectionInformation.Options = &SapPacketType;
  2560. pIrpContext->ConnectionInformation.RemoteAddressLength = sizeof(TA_IPX_ADDRESS);
  2561. pIrpContext->ConnectionInformation.RemoteAddress = &pIrpContext->Destination;
  2562. BuildIpxAddress(
  2563. ((PTA_IPX_ADDRESS)SourceAddress)->Address[0].Address[0].NetworkAddress,
  2564. ((PTA_IPX_ADDRESS)SourceAddress)->Address[0].Address[0].NodeAddress,
  2565. ((PTA_IPX_ADDRESS)SourceAddress)->Address[0].Address[0].Socket,
  2566. &pIrpContext->Destination);
  2567. TdiBuildSendDatagram(
  2568. pIrpContext->pOriginalIrp,
  2569. pNpScb->WatchDog.pDeviceObject,
  2570. pNpScb->WatchDog.pFileObject,
  2571. &CompletionWatchDogSend,
  2572. pIrpContext,
  2573. pIrpContext->TxMdl,
  2574. MdlLength(pIrpContext->TxMdl),
  2575. &pIrpContext->ConnectionInformation);
  2576. IoCallDriver(
  2577. pNpScb->WatchDog.pDeviceObject,
  2578. pIrpContext->pOriginalIrp );
  2579. }
  2580. DebugTrace(-1, Dbg, " %lx\n", STATUS_DATA_NOT_ACCEPTED);
  2581. return STATUS_DATA_NOT_ACCEPTED;
  2582. UNREFERENCED_PARAMETER( SourceAddressLength );
  2583. UNREFERENCED_PARAMETER( BytesIndicated );
  2584. UNREFERENCED_PARAMETER( BytesAvailable );
  2585. UNREFERENCED_PARAMETER( BytesTaken );
  2586. UNREFERENCED_PARAMETER( Tsdu );
  2587. UNREFERENCED_PARAMETER( OptionsLength );
  2588. UNREFERENCED_PARAMETER( Options );
  2589. }
  2590. NTSTATUS
  2591. CompletionWatchDogSend(
  2592. IN PDEVICE_OBJECT DeviceObject,
  2593. IN PIRP Irp,
  2594. IN PVOID Context
  2595. )
  2596. /*++
  2597. Routine Description:
  2598. This routine does not complete the Irp. It is used to signal to a
  2599. synchronous part of the driver that it can proceed.
  2600. Arguments:
  2601. DeviceObject - unused.
  2602. Irp - Supplies Irp that the transport has finished processing.
  2603. Context - Supplies the IrpContext associated with the Irp.
  2604. Return Value:
  2605. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  2606. processing Irp stack locations at this point.
  2607. --*/
  2608. {
  2609. PIRP_CONTEXT pIrpC = (PIRP_CONTEXT) Context;
  2610. //
  2611. // Avoid completing the Irp because the Mdl etc. do not contain
  2612. // their original values.
  2613. //
  2614. DebugTrace( +1, Dbg, "CompletionWatchDogSend\n", 0);
  2615. DebugTrace( +0, Dbg, "Irp %X\n", Irp);
  2616. DebugTrace( -1, Dbg, "pIrpC %X\n", pIrpC);
  2617. FREE_IRP( pIrpC->pOriginalIrp );
  2618. pIrpC->pOriginalIrp = NULL; // Avoid FreeIrpContext modifying freed Irp.
  2619. FreeIrpContext( pIrpC );
  2620. return STATUS_MORE_PROCESSING_REQUIRED;
  2621. UNREFERENCED_PARAMETER( DeviceObject );
  2622. UNREFERENCED_PARAMETER( Irp );
  2623. }
  2624. NTSTATUS
  2625. SendDatagramHandler(
  2626. IN PVOID TdiEventContext,
  2627. IN int SourceAddressLength,
  2628. IN PVOID SourceAddress,
  2629. IN int OptionsLength,
  2630. IN PVOID Options,
  2631. IN ULONG ReceiveDatagramFlags,
  2632. IN ULONG BytesIndicated,
  2633. IN ULONG BytesAvailable,
  2634. OUT ULONG *BytesTaken,
  2635. IN PVOID Tsdu,
  2636. OUT PIRP *IoRequestPacket
  2637. )
  2638. /*++
  2639. Routine Description:
  2640. This routine is the receive datagram event indication handler for the
  2641. Server socket.
  2642. Arguments:
  2643. TdiEventContext - Context provided for this event, a pointer to the
  2644. non paged SCB.
  2645. SourceAddressLength - Length of the originator of the datagram.
  2646. SourceAddress - String describing the originator of the datagram.
  2647. OptionsLength - Length of the buffer pointed to by Options.
  2648. Options - Options for the receive.
  2649. ReceiveDatagramFlags - Ignored.
  2650. BytesIndicated - Number of bytes this indication.
  2651. BytesAvailable - Number of bytes in complete Tsdu.
  2652. BytesTaken - Returns the number of bytes used.
  2653. Tsdu - Pointer describing this TSDU, typically a lump of bytes.
  2654. IoRequestPacket - TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  2655. Return Value:
  2656. NTSTATUS - Status of receive operation
  2657. --*/
  2658. {
  2659. PNONPAGED_SCB pNpScb = (PNONPAGED_SCB)TdiEventContext;
  2660. PUCHAR RspData = (PUCHAR)Tsdu;
  2661. PIRP_CONTEXT pIrpContext;
  2662. PLIST_ENTRY listEntry;
  2663. PIRP Irp;
  2664. *IoRequestPacket = NULL;
  2665. DebugTrace(0, Dbg, "SendDatagramHandler\n", 0);
  2666. Stats.NcpsReceived.QuadPart++;
  2667. Stats.BytesReceived.QuadPart += BytesAvailable;
  2668. //
  2669. // Transport will complete the processing of the request, we don't
  2670. // want the datagram.
  2671. //
  2672. DebugTrace(+1, Dbg, "SendDatagramHandler\n", 0);
  2673. DebugTrace(+0, Dbg, "SourceAddressLength %x\n", SourceAddressLength);
  2674. DebugTrace(+0, Dbg, "BytesIndicated %x\n", BytesIndicated);
  2675. DebugTrace(+0, Dbg, "BytesAvailable %x\n", BytesAvailable);
  2676. DebugTrace(+0, Dbg, "BytesTaken %x\n", *BytesTaken);
  2677. //
  2678. // SourceAddress is the address of the server or the bridge tbat sent
  2679. // the packet.
  2680. //
  2681. #if NWDBG
  2682. dump( Dbg, SourceAddress, SourceAddressLength );
  2683. dump( Dbg, Tsdu, BytesIndicated );
  2684. #endif
  2685. if (pNpScb->NodeTypeCode != NW_NTC_SCBNP ) {
  2686. DebugTrace(+0, Dbg, "nwrdr: Invalid SendDatagram Indication %x\n", pNpScb );
  2687. #if DBG
  2688. DbgBreakPoint();
  2689. #endif
  2690. return STATUS_DATA_NOT_ACCEPTED;
  2691. }
  2692. if (RspData[1] == BROADCAST_MESSAGE_WAITING ) {
  2693. //
  2694. // Broadcast message waiting. If the scavenger
  2695. // isn't running, it's safe to go get it.
  2696. //
  2697. KeAcquireSpinLockAtDpcLevel( &NwScavengerSpinLock );
  2698. if ( WorkerRunning ) {
  2699. //
  2700. // The scavenger is running, we can't pick up this
  2701. // message until the scavenger is done!
  2702. //
  2703. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "Delaying get message for scavenger.\n", 0 );
  2704. KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock );
  2705. } else {
  2706. //
  2707. // Make sure the scavenger doesn't start.
  2708. //
  2709. WorkerRunning = TRUE;
  2710. KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock );
  2711. listEntry = ExInterlockedRemoveHeadList(
  2712. &NwGetMessageList,
  2713. &NwMessageSpinLock );
  2714. if ( listEntry != NULL ) {
  2715. pIrpContext = CONTAINING_RECORD( listEntry, IRP_CONTEXT, NextRequest );
  2716. //
  2717. // Clear the cancel routine for this IRP.
  2718. //
  2719. Irp = pIrpContext->pOriginalIrp;
  2720. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2721. IoSetCancelRoutine( Irp, NULL );
  2722. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2723. pIrpContext->PostProcessRoutine = FspGetMessage;
  2724. pIrpContext->pNpScb = pNpScb;
  2725. pIrpContext->pScb = pNpScb->pScb;
  2726. NwPostToFsp( pIrpContext, TRUE );
  2727. } else {
  2728. WorkerRunning = FALSE;
  2729. }
  2730. }
  2731. }
  2732. DebugTrace(-1, Dbg, " %lx\n", STATUS_DATA_NOT_ACCEPTED);
  2733. return STATUS_DATA_NOT_ACCEPTED;
  2734. UNREFERENCED_PARAMETER( SourceAddressLength );
  2735. UNREFERENCED_PARAMETER( BytesIndicated );
  2736. UNREFERENCED_PARAMETER( BytesAvailable );
  2737. UNREFERENCED_PARAMETER( BytesTaken );
  2738. UNREFERENCED_PARAMETER( Tsdu );
  2739. UNREFERENCED_PARAMETER( OptionsLength );
  2740. UNREFERENCED_PARAMETER( Options );
  2741. }
  2742. NTSTATUS
  2743. FspGetMessage(
  2744. IN PIRP_CONTEXT IrpContext
  2745. )
  2746. /*++
  2747. Routine Description:
  2748. This routine continues process a broadcast message waiting message.
  2749. Arguments:
  2750. pIrpContext - A pointer to the IRP context information for the
  2751. request in progress.
  2752. Return Value:
  2753. The status of the operation.
  2754. --*/
  2755. {
  2756. KIRQL OldIrql;
  2757. PLIST_ENTRY ScbQueueEntry;
  2758. PNONPAGED_SCB pNpScb;
  2759. BOOLEAN bFound = FALSE;
  2760. UNICODE_STRING Message;
  2761. NTSTATUS Status;
  2762. PNWR_SERVER_MESSAGE ServerMessage;
  2763. PUNICODE_STRING ServerName;
  2764. ULONG MessageLength;
  2765. short int i;
  2766. PAGED_CODE();
  2767. NwReferenceUnlockableCodeSection();
  2768. //
  2769. // The Scb may be being deleted so carefully walk the list and reference it if
  2770. // we find it.
  2771. //
  2772. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  2773. ScbQueueEntry = ScbQueue.Flink;
  2774. while ( ScbQueueEntry != &ScbQueue ) {
  2775. pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
  2776. if (pNpScb == IrpContext->pNpScb ) {
  2777. NwReferenceScb( pNpScb );
  2778. bFound = TRUE;
  2779. break;
  2780. }
  2781. ScbQueueEntry = ScbQueueEntry->Flink;
  2782. }
  2783. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  2784. if (!bFound) {
  2785. //
  2786. // Server deleted. Its easiest to continue processing the IrpContext
  2787. // with an error than try to recover it and return it to the queue.
  2788. //
  2789. Status = STATUS_UNSUCCESSFUL;
  2790. NwDereferenceUnlockableCodeSection();
  2791. //
  2792. // Re-enable the scavenger before we return!
  2793. //
  2794. WorkerRunning = FALSE;
  2795. return( Status );
  2796. }
  2797. //
  2798. // If the message is telling us that the server is going down then don't
  2799. // work too hard trying to get the message. The server is persistent with
  2800. // respect to other messages so we'll come through here again when the
  2801. // problem has been resolved.
  2802. //
  2803. SetFlag( IrpContext->Flags, IRP_FLAG_REROUTE_ATTEMPTED );
  2804. if ( UP_LEVEL_SERVER( IrpContext->pScb ) ) {
  2805. Status = ExchangeWithWait(
  2806. IrpContext,
  2807. SynchronousResponseCallback,
  2808. "S",
  2809. NCP_MESSAGE_FUNCTION, NCP_GET_ENTIRE_MESSAGE );
  2810. } else {
  2811. Status = ExchangeWithWait(
  2812. IrpContext,
  2813. SynchronousResponseCallback,
  2814. "S",
  2815. NCP_MESSAGE_FUNCTION, NCP_GET_MESSAGE );
  2816. }
  2817. if ( !NT_SUCCESS( Status ) ) {
  2818. NwDereferenceScb( pNpScb );
  2819. NwDereferenceUnlockableCodeSection();
  2820. //
  2821. // Re-enable the scavenger before we return!
  2822. //
  2823. WorkerRunning = FALSE;
  2824. return( Status );
  2825. }
  2826. ServerMessage = (PNWR_SERVER_MESSAGE)IrpContext->Specific.FileSystemControl.Buffer;
  2827. MessageLength = IrpContext->Specific.FileSystemControl.Length;
  2828. ServerName = &IrpContext->pNpScb->ServerName;
  2829. if ( ServerName->Length + FIELD_OFFSET( NWR_SERVER_MESSAGE, Server ) + sizeof(WCHAR) > MessageLength ) {
  2830. Status = STATUS_BUFFER_TOO_SMALL;
  2831. NwDereferenceScb( pNpScb );
  2832. NwDereferenceUnlockableCodeSection();
  2833. //
  2834. // Re-enable the scavenger before we return!
  2835. //
  2836. WorkerRunning = FALSE;
  2837. return( Status );
  2838. } else {
  2839. // --- Multi-user -------------
  2840. // Need Login ID to send messages
  2841. //
  2842. ServerMessage->LogonId = *((PLUID)&IrpContext->pScb->UserUid);
  2843. //
  2844. // Copy the server name to the output buffer.
  2845. //
  2846. ServerMessage->MessageOffset =
  2847. ServerName->Length +
  2848. FIELD_OFFSET( NWR_SERVER_MESSAGE, Server ) +
  2849. sizeof(WCHAR);
  2850. RtlMoveMemory(
  2851. ServerMessage->Server,
  2852. ServerName->Buffer,
  2853. ServerName->Length );
  2854. ServerMessage->Server[ ServerName->Length / sizeof(WCHAR) ] = L'\0';
  2855. }
  2856. //
  2857. // Copy the message to the user's buffer.
  2858. //
  2859. Message.Buffer = &ServerMessage->Server[ ServerName->Length / sizeof(WCHAR) ] + 1;
  2860. Message.MaximumLength = (USHORT)( MessageLength - ( ServerName->Length + FIELD_OFFSET( NWR_SERVER_MESSAGE, Server ) + sizeof(WCHAR) ) );
  2861. if ( NT_SUCCESS( Status) ) {
  2862. Status = ParseResponse(
  2863. IrpContext,
  2864. IrpContext->rsp,
  2865. IrpContext->ResponseLength,
  2866. "NP",
  2867. &Message );
  2868. }
  2869. if ( !NT_SUCCESS( Status ) ) {
  2870. NwDereferenceScb( pNpScb );
  2871. NwDereferenceUnlockableCodeSection();
  2872. //
  2873. // Re-enable the scavenger before we return!
  2874. //
  2875. WorkerRunning = FALSE;
  2876. return( Status );
  2877. }
  2878. //
  2879. // Strip the trailing spaces and append a NUL terminator to the message.
  2880. //
  2881. for ( i = Message.Length / sizeof(WCHAR) - 1; i >= 0 ; i-- ) {
  2882. if ( Message.Buffer[ i ] != L' ') {
  2883. Message.Length = (i + 1) * sizeof(WCHAR);
  2884. break;
  2885. }
  2886. }
  2887. if ( Message.Length > 0 ) {
  2888. Message.Buffer[ Message.Length / sizeof(WCHAR) ] = L'\0';
  2889. }
  2890. IrpContext->pOriginalIrp->IoStatus.Information =
  2891. ServerName->Length +
  2892. FIELD_OFFSET( NWR_SERVER_MESSAGE, Server ) + sizeof(WCHAR) +
  2893. Message.Length + sizeof(WCHAR);
  2894. NwDereferenceScb( pNpScb );
  2895. NwDereferenceUnlockableCodeSection();
  2896. //
  2897. // Re-enable the scavenger before we return!
  2898. //
  2899. WorkerRunning = FALSE;
  2900. return( Status );
  2901. }
  2902. NTSTATUS
  2903. _cdecl
  2904. ExchangeWithWait(
  2905. PIRP_CONTEXT pIrpContext,
  2906. PEX pEx,
  2907. char* f,
  2908. ... // format specific parameters
  2909. )
  2910. /*++
  2911. Routine Description:
  2912. This routine sends a NCP packet and waits for the response.
  2913. Arguments:
  2914. pIrpContext - A pointer to the context information for this IRP.
  2915. pEX, Context, f - See _Exchange
  2916. Return Value:
  2917. NTSTATUS - Status of the operation.
  2918. --*/
  2919. {
  2920. NTSTATUS Status;
  2921. va_list Arguments;
  2922. PAGED_CODE();
  2923. //KeResetEvent( &pIrpContext->Event );
  2924. va_start( Arguments, f );
  2925. Status = FormatRequest( pIrpContext, pEx, f, Arguments );
  2926. if ( !NT_SUCCESS( Status )) {
  2927. return( Status );
  2928. }
  2929. va_end( Arguments );
  2930. Status = PrepareAndSendPacket( pIrpContext );
  2931. if ( !NT_SUCCESS( Status )) {
  2932. return( Status );
  2933. }
  2934. Status = KeWaitForSingleObject(
  2935. &pIrpContext->Event,
  2936. Executive,
  2937. KernelMode,
  2938. FALSE,
  2939. NULL
  2940. );
  2941. if ( !NT_SUCCESS( Status )) {
  2942. return( Status );
  2943. }
  2944. Status = pIrpContext->pOriginalIrp->IoStatus.Status;
  2945. if ( NT_SUCCESS( Status ) &&
  2946. pIrpContext->PacketType != SAP_BROADCAST ) {
  2947. Status = NwErrorToNtStatus( pIrpContext->ResponseParameters.Error );
  2948. }
  2949. return( Status );
  2950. }
  2951. BOOLEAN
  2952. VerifyResponse(
  2953. PIRP_CONTEXT pIrpContext,
  2954. PVOID Response
  2955. )
  2956. /*++
  2957. Routine Description:
  2958. This routine verifies that a received response is the expected
  2959. response for the current request.
  2960. Arguments:
  2961. pIrpContext - A pointer to the context information for this IRP.
  2962. Response - A pointer to the buffer containing the response.
  2963. Return Value:
  2964. TRUE - This is a valid response.
  2965. FALSE - This is an invalid response.
  2966. --*/
  2967. {
  2968. PNCP_RESPONSE pNcpResponse;
  2969. PNONPAGED_SCB pNpScb;
  2970. pNcpResponse = (PNCP_RESPONSE)Response;
  2971. pNpScb = pIrpContext->pNpScb;
  2972. if ( pNcpResponse->NcpHeader.ConnectionIdLow != pNpScb->ConnectionNo ) {
  2973. DebugTrace(+0, Dbg, "VerifyResponse, bad connection number\n", 0);
  2974. return( FALSE );
  2975. }
  2976. if ( pNcpResponse->NcpHeader.SequenceNumber != pNpScb->SequenceNo ) {
  2977. DebugTrace(+1, Dbg, "VerifyResponse, bad sequence number %x\n", 0);
  2978. DebugTrace(+0, Dbg, " pNcpResponse->NcpHeader.SequenceNumber %x\n",
  2979. pNcpResponse->NcpHeader.SequenceNumber);
  2980. DebugTrace(-1, Dbg, " pNpScb->SequenceNo %x\n", pNpScb->SequenceNo );
  2981. return( FALSE );
  2982. }
  2983. return( TRUE );
  2984. }
  2985. VOID
  2986. ScheduleReconnectRetry(
  2987. PIRP_CONTEXT pIrpContext
  2988. )
  2989. /*++
  2990. Routine Description:
  2991. This routine schedules an a reconnect attempt, and then resubmits
  2992. our request if the reconnect was successful.
  2993. Arguments:
  2994. pIrpContext - A pointer to the context information for this IRP.
  2995. Return Value:
  2996. None.
  2997. --*/
  2998. {
  2999. PWORK_CONTEXT workContext;
  3000. if (WorkerThreadRunning == TRUE) {
  3001. //
  3002. // Prepare the work context
  3003. //
  3004. workContext = AllocateWorkContext();
  3005. if (workContext == NULL) {
  3006. pIrpContext->pEx( pIrpContext, 0, NULL );
  3007. return;
  3008. }
  3009. workContext->pIrpC = pIrpContext;
  3010. workContext->NodeWorkCode = NWC_NWC_RECONNECT;
  3011. //
  3012. // and queue it.
  3013. //
  3014. DebugTrace( 0, Dbg, "Queueing reconnect work.\n", 0 );
  3015. KeInsertQueue( &KernelQueue,
  3016. &workContext->Next
  3017. );
  3018. } else {
  3019. //
  3020. // The worker thread is not running...
  3021. //
  3022. pIrpContext->pEx( pIrpContext, 0, NULL );
  3023. return;
  3024. }
  3025. }
  3026. VOID
  3027. ReconnectRetry(
  3028. IN PIRP_CONTEXT pIrpContext
  3029. )
  3030. /*++
  3031. Routine Description:
  3032. This routine attempts to reconnect to a disconnected server. If it
  3033. is successful it resubmits an existing request.
  3034. Arguments:
  3035. pIrpContext - A pointer to the context information for this IRP.
  3036. Return Value:
  3037. None.
  3038. --*/
  3039. {
  3040. PIRP_CONTEXT pNewIrpContext;
  3041. PSCB pScb, pNewScb;
  3042. PNONPAGED_SCB pNpScb;
  3043. NTSTATUS Status;
  3044. PAGED_CODE();
  3045. pNpScb = pIrpContext->pNpScb;
  3046. pScb = pNpScb->pScb;
  3047. Stats.Reconnects++;
  3048. if ( pScb == NULL ) {
  3049. pScb = pNpScb->pScb;
  3050. pIrpContext->pScb = pScb;
  3051. }
  3052. //
  3053. // Allocate a temporary IRP context to use to reconnect to the server
  3054. //
  3055. if ( !NwAllocateExtraIrpContext( &pNewIrpContext, pNpScb ) ) {
  3056. pIrpContext->pEx( pIrpContext, 0, NULL );
  3057. return;
  3058. }
  3059. pNewIrpContext->Specific.Create.UserUid = pScb->UserUid;
  3060. pNewIrpContext->pNpScb = pNpScb;
  3061. pNewIrpContext->pScb = pScb;
  3062. //
  3063. // Reset the sequence numbers.
  3064. //
  3065. pNpScb->SequenceNo = 0;
  3066. pNpScb->BurstSequenceNo = 0;
  3067. pNpScb->BurstRequestNo = 0;
  3068. //
  3069. // Now insert this new IrpContext to the head of the SCB queue for
  3070. // processing. We can get away with this because we own the IRP context
  3071. // currently at the front of the queue. With the RECONNECT_ATTEMPT
  3072. // flag set, ConnectScb() will not remove us from the head of the queue.
  3073. //
  3074. SetFlag( pNewIrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  3075. SetFlag( pNewIrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT );
  3076. ExInterlockedInsertHeadList(
  3077. &pNpScb->Requests,
  3078. &pNewIrpContext->NextRequest,
  3079. &pNpScb->NpScbSpinLock );
  3080. pNewScb = pNpScb->pScb;
  3081. Status = ConnectScb( &pNewScb,
  3082. pNewIrpContext,
  3083. &pNpScb->ServerName,
  3084. NULL,
  3085. NULL,
  3086. NULL,
  3087. FALSE,
  3088. FALSE,
  3089. TRUE );
  3090. if ( !NT_SUCCESS( Status ) ) {
  3091. //
  3092. // Couldn't reconnect. Free the extra IRP context, complete the
  3093. // original request with an error.
  3094. //
  3095. NwDequeueIrpContext( pNewIrpContext, FALSE );
  3096. NwFreeExtraIrpContext( pNewIrpContext );
  3097. pIrpContext->pEx( pIrpContext, 0, NULL );
  3098. return;
  3099. }
  3100. ASSERT( pNewScb == pScb );
  3101. //
  3102. // Try to reconnect the VCBs.
  3103. //
  3104. NwReopenVcbHandlesForScb( pNewIrpContext, pScb );
  3105. //
  3106. // Dequeue and free the bonus IRP context.
  3107. //
  3108. NwDequeueIrpContext( pNewIrpContext, FALSE );
  3109. NwFreeExtraIrpContext( pNewIrpContext );
  3110. //
  3111. // Resubmit the original request, with a new sequence number. Note that
  3112. // it's back at the front of the queue, but no longer reconnectable.
  3113. //
  3114. pIrpContext->req[2] = pNpScb->SequenceNo;
  3115. pIrpContext->req[3] = pNpScb->ConnectionNo;
  3116. pIrpContext->req[5] = pNpScb->ConnectionNoHigh;
  3117. PreparePacket( pIrpContext, pIrpContext->pOriginalIrp, pIrpContext->TxMdl );
  3118. SendNow( pIrpContext );
  3119. return;
  3120. }
  3121. NTSTATUS
  3122. NewRouteRetry(
  3123. IN PIRP_CONTEXT pIrpContext
  3124. )
  3125. /*++
  3126. Routine Description:
  3127. This routine attempts to establish a new route to a non-responding server.
  3128. If it is successful it resubmits the request in progress.
  3129. Arguments:
  3130. pIrpContext - A pointer to the context information for this IRP.
  3131. Return Value:
  3132. None.
  3133. --*/
  3134. {
  3135. NTSTATUS Status;
  3136. PNONPAGED_SCB pNpScb = pIrpContext->pNpScb;
  3137. LARGE_INTEGER CurrentTime = {0, 0};
  3138. PAGED_CODE();
  3139. //
  3140. // Don't bother to re-rip if we are shutting down.
  3141. //
  3142. if ( NwRcb.State != RCB_STATE_SHUTDOWN ) {
  3143. Status = GetNewRoute( pIrpContext );
  3144. } else {
  3145. Status = STATUS_REMOTE_NOT_LISTENING;
  3146. }
  3147. //
  3148. // Ask the transport to establish a new route to the server.
  3149. //
  3150. if ( !NT_SUCCESS( Status ) ) {
  3151. //
  3152. // Attempt to get new route failed, fail the current request.
  3153. //
  3154. pIrpContext->ResponseParameters.Error = ERROR_UNEXP_NET_ERR;
  3155. pIrpContext->pEx( pIrpContext, 0, NULL );
  3156. if ( pNpScb != &NwPermanentNpScb ) {
  3157. KeQuerySystemTime( &CurrentTime );
  3158. if ( CanLogTimeOutEvent( pNpScb->NwNextEventTime,
  3159. CurrentTime
  3160. )) {
  3161. LPWSTR serverName = pNpScb->ServerName.Buffer;
  3162. if (serverName == NULL) {
  3163. serverName = L"";
  3164. }
  3165. Error(
  3166. EVENT_NWRDR_TIMEOUT,
  3167. STATUS_UNEXPECTED_NETWORK_ERROR,
  3168. NULL,
  3169. 0,
  3170. 1,
  3171. serverName);
  3172. //
  3173. // Set the LastEventTime to the CurrentTime
  3174. //
  3175. UpdateNextEventTime(
  3176. pNpScb->NwNextEventTime,
  3177. CurrentTime,
  3178. TimeOutEventInterval
  3179. );
  3180. }
  3181. pNpScb->State = SCB_STATE_ATTACHING;
  3182. }
  3183. } else {
  3184. //
  3185. // Got a new route, resubmit the request. Allow retries
  3186. // with the new route.
  3187. //
  3188. pIrpContext->pNpScb->RetryCount = DefaultRetryCount / 2;
  3189. PreparePacket( pIrpContext, pIrpContext->pOriginalIrp, pIrpContext->TxMdl );
  3190. SendNow( pIrpContext );
  3191. }
  3192. //
  3193. // Return STATUS_PENDING so that the FSP dispatcher doesn't complete
  3194. // this request.
  3195. //
  3196. return( STATUS_PENDING );
  3197. }
  3198. NTSTATUS
  3199. NewRouteBurstRetry(
  3200. IN PIRP_CONTEXT pIrpContext
  3201. )
  3202. /*++
  3203. Routine Description:
  3204. This routine attempts to establish a new route to a non-responding server.
  3205. If it is successful it resubmits the request in progress.
  3206. Arguments:
  3207. pIrpContext - A pointer to the context information for this IRP.
  3208. Return Value:
  3209. None.
  3210. --*/
  3211. {
  3212. NTSTATUS Status;
  3213. PIRP_CONTEXT pNewIrpContext;
  3214. PNONPAGED_SCB pNpScb = pIrpContext->pNpScb;
  3215. BOOLEAN LIPNegotiated ;
  3216. LARGE_INTEGER CurrentTime = {0, 0};
  3217. PAGED_CODE();
  3218. //
  3219. // Don't bother to re-rip if we are shutting down.
  3220. //
  3221. if ( NwRcb.State == RCB_STATE_SHUTDOWN ) {
  3222. return( STATUS_REMOTE_NOT_LISTENING );
  3223. }
  3224. //
  3225. // Ask the transport to establish a new route to the server.
  3226. //
  3227. Status = GetNewRoute( pIrpContext );
  3228. if ( NT_SUCCESS( Status ) ) {
  3229. //
  3230. // If this is a burst write, we must first complete the write
  3231. // request (there is no way to tell the server to abandon the write).
  3232. //
  3233. // Set packet size down to 512 to guarantee that the packets will be
  3234. // forwarded, and resend the burst data. Queue the new IRP context
  3235. // behind the burst write, so that we can establish a new burst
  3236. // connection.
  3237. //
  3238. // Note that ResubmitBurstWrite may complete the request and
  3239. // free the IrpContext.
  3240. //
  3241. pNpScb->RetryCount = DefaultRetryCount / 2;
  3242. if ( BooleanFlagOn( pIrpContext->Flags, IRP_FLAG_BURST_WRITE ) ) {
  3243. Status = ResubmitBurstWrite( pIrpContext );
  3244. } else {
  3245. //
  3246. // Allocate a temporary IRP context to use to reconnect to the server
  3247. //
  3248. if ( NT_SUCCESS( Status ) ) {
  3249. if ( !NwAllocateExtraIrpContext( &pNewIrpContext, pNpScb ) ) {
  3250. Status = STATUS_INSUFFICIENT_RESOURCES;
  3251. } else {
  3252. pNewIrpContext->Specific.Create.UserUid = pIrpContext->Specific.Create.UserUid;
  3253. SetFlag( pNewIrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  3254. SetFlag( pNewIrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT );
  3255. //
  3256. // Since we're doing this from a worker thread, we can't
  3257. // let the dpc timer schedule _another_ worker thread
  3258. // request if this also times out or we may deadlock
  3259. // the delayed work queue.
  3260. //
  3261. SetFlag( pNewIrpContext->Flags, IRP_FLAG_REROUTE_ATTEMPTED );
  3262. pNewIrpContext->pNpScb = pNpScb;
  3263. }
  3264. }
  3265. if ( NT_SUCCESS( Status ) ) {
  3266. //
  3267. // Insert this new IrpContext to the head of
  3268. // the SCB queue for processing. We can get away with this
  3269. // because we own the IRP context currently at the front of
  3270. // the queue.
  3271. //
  3272. ExInterlockedInsertHeadList(
  3273. &pNpScb->Requests,
  3274. &pNewIrpContext->NextRequest,
  3275. &pNpScb->NpScbSpinLock );
  3276. //
  3277. // Now prepare to resend the burst read.
  3278. //
  3279. PreparePacket( pIrpContext, pIrpContext->pOriginalIrp, pIrpContext->TxMdl );
  3280. //
  3281. // Renegotiate the burst connection, this will automatically re-sync
  3282. // the burst connection.
  3283. //
  3284. // TRACKING: We lose sizeof( NCP_BURST_WRITE_REQUEST ) each time
  3285. // we do this right now.
  3286. //
  3287. NegotiateBurstMode( pNewIrpContext, pNpScb, &LIPNegotiated );
  3288. //
  3289. // Reset the sequence numbers.
  3290. //
  3291. pNpScb->BurstSequenceNo = 0;
  3292. pNpScb->BurstRequestNo = 0;
  3293. //
  3294. // Dequeue and free the bonus IRP context.
  3295. //
  3296. ASSERT( pNpScb->Requests.Flink == &pNewIrpContext->NextRequest );
  3297. ExInterlockedRemoveHeadList(
  3298. &pNpScb->Requests,
  3299. &pNpScb->NpScbSpinLock );
  3300. ClearFlag( pNewIrpContext->Flags, IRP_FLAG_ON_SCB_QUEUE );
  3301. NwFreeExtraIrpContext( pNewIrpContext );
  3302. //
  3303. // Got a new route, resubmit the request
  3304. //
  3305. Status = ResubmitBurstRead( pIrpContext );
  3306. }
  3307. }
  3308. }
  3309. if ( !NT_SUCCESS( Status ) ) {
  3310. //
  3311. // Attempt to get new route failed, fail the current request.
  3312. //
  3313. pIrpContext->ResponseParameters.Error = ERROR_UNEXP_NET_ERR;
  3314. pIrpContext->pEx( pIrpContext, 0, NULL );
  3315. if ( pNpScb != &NwPermanentNpScb ) {
  3316. KeQuerySystemTime( &CurrentTime );
  3317. if ( CanLogTimeOutEvent( pNpScb->NwNextEventTime,
  3318. CurrentTime
  3319. )) {
  3320. Error(
  3321. EVENT_NWRDR_TIMEOUT,
  3322. STATUS_UNEXPECTED_NETWORK_ERROR,
  3323. NULL,
  3324. 0,
  3325. 1,
  3326. pNpScb->ServerName.Buffer );
  3327. //
  3328. // Set the LastEventTime to the CurrentTime
  3329. //
  3330. UpdateNextEventTime(
  3331. pNpScb->NwNextEventTime,
  3332. CurrentTime,
  3333. TimeOutEventInterval
  3334. );
  3335. }
  3336. }
  3337. }
  3338. //
  3339. // Return STATUS_PENDING so that the FSP dispatcher doesn't complete
  3340. // this request.
  3341. //
  3342. return( STATUS_PENDING );
  3343. }
  3344. NTSTATUS
  3345. FspProcessServerDown(
  3346. PIRP_CONTEXT IrpContext
  3347. )
  3348. /*++
  3349. Routine Description:
  3350. This routine process a response with the server shutdown bit set.
  3351. It close all open handles for the server, and puts the server in
  3352. the attaching state.
  3353. Arguments:
  3354. pIrpContext - A pointer to the context information for this IRP.
  3355. Return Value:
  3356. STATUS_PENDING.
  3357. --*/
  3358. {
  3359. KIRQL OldIrql;
  3360. PNONPAGED_SCB pNpScb = IrpContext->pNpScb;
  3361. //
  3362. // Avoid the Scb from disappearing under us.
  3363. //
  3364. NwReferenceScb( pNpScb );
  3365. //
  3366. // Move the IrpContext from the front of the queue just in-case it
  3367. // owns the Rcb.
  3368. //
  3369. KeAcquireSpinLock( &IrpContext->pNpScb->NpScbSpinLock, &OldIrql );
  3370. if ( IrpContext->pNpScb->Sending ) {
  3371. //
  3372. // Let send completion call the pEx routine
  3373. //
  3374. IrpContext->pNpScb->Received = TRUE;
  3375. KeReleaseSpinLock( &IrpContext->pNpScb->NpScbSpinLock, OldIrql );
  3376. } else {
  3377. IrpContext->pNpScb->Receiving = FALSE;
  3378. IrpContext->pNpScb->Received = FALSE;
  3379. KeReleaseSpinLock( &IrpContext->pNpScb->NpScbSpinLock, OldIrql );
  3380. //
  3381. // Now call the callback routine.
  3382. //
  3383. IrpContext->pEx(
  3384. IrpContext,
  3385. IrpContext->ResponseLength,
  3386. IrpContext->rsp );
  3387. }
  3388. //
  3389. // Close all active handles for this server.
  3390. //
  3391. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  3392. NwInvalidateAllHandlesForScb( pNpScb->pScb );
  3393. NwReleaseRcb( &NwRcb );
  3394. NwDereferenceScb( pNpScb );
  3395. //
  3396. // Return STATUS_PENDING so that the FSP process doesn't complete
  3397. // this request.
  3398. //
  3399. return( STATUS_PENDING );
  3400. }
  3401. VOID
  3402. NwProcessSendBurstFailure(
  3403. PNONPAGED_SCB NpScb,
  3404. USHORT MissingFragmentCount
  3405. )
  3406. /*++
  3407. Routine Description:
  3408. This routine adjust burst parameters after an unsuccessful burst operation.
  3409. Arguments:
  3410. NpScb - A pointer to the SCB that has experienced a burst failure.
  3411. MissingFragmentCount - A measure of how many chunks were lost.
  3412. Return Value:
  3413. None.
  3414. --*/
  3415. {
  3416. LONG temp;
  3417. DebugTrace( 0, DEBUG_TRACE_LIP, "Burst failure, NpScb = %X\n", NpScb );
  3418. if ( NpScb->NwSendDelay != NpScb->CurrentBurstDelay ) {
  3419. //
  3420. // This burst has already failed
  3421. //
  3422. return;
  3423. }
  3424. NpScb->NwBadSendDelay = NpScb->NwSendDelay;
  3425. //
  3426. // Add to the send delay. Never let it go above 5000ms.
  3427. //
  3428. temp = NpScb->NwGoodSendDelay - NpScb->NwBadSendDelay;
  3429. if (temp >= 0) {
  3430. NpScb->NwSendDelay += temp + 2;
  3431. } else {
  3432. NpScb->NwSendDelay += -temp + 2;
  3433. }
  3434. if ( NpScb->NwSendDelay > NpScb->NwMaxSendDelay ) {
  3435. NpScb->NwSendDelay = NpScb->NwMaxSendDelay;
  3436. //
  3437. // If we have slowed down a lot then it might be that the server or a
  3438. // bridge only has a small buffer on its NIC. If this is the case then
  3439. // rather than sending a big burst with long even gaps between the
  3440. // packets, we should try to send a burst the size of the buffer.
  3441. //
  3442. if ( !DontShrink ) {
  3443. if (((NpScb->MaxSendSize - 1) / NpScb->MaxPacketSize) > 2 ) {
  3444. // Round down to the next packet
  3445. NpScb->MaxSendSize = ((NpScb->MaxSendSize - 1) / NpScb->MaxPacketSize) * NpScb->MaxPacketSize;
  3446. //
  3447. // Adjust SendDelay below threshold to see if things improve before
  3448. // we shrink the size again.
  3449. //
  3450. NpScb->NwSendDelay = NpScb->NwGoodSendDelay = NpScb->NwBadSendDelay = MinSendDelay;
  3451. } else {
  3452. //
  3453. // We reached the minimum size with the maximum delay. Give up on burst.
  3454. //
  3455. NpScb->SendBurstModeEnabled = FALSE;
  3456. }
  3457. }
  3458. }
  3459. NpScb->NtSendDelay.QuadPart = NpScb->NwSendDelay * -1000 ;
  3460. DebugTrace( 0, DEBUG_TRACE_LIP, "New Send Delay = %d\n", NpScb->NwSendDelay );
  3461. NpScb->SendBurstSuccessCount = 0;
  3462. }
  3463. VOID
  3464. NwProcessReceiveBurstFailure(
  3465. PNONPAGED_SCB NpScb,
  3466. USHORT MissingFragmentCount
  3467. )
  3468. /*++
  3469. Routine Description:
  3470. This routine adjust burst parameters after an unsuccessful burst operation.
  3471. Arguments:
  3472. NpScb - A pointer to the SCB that has experienced a burst failure.
  3473. MissingFragmentCount - A measure of how many chunks were lost.
  3474. Return Value:
  3475. None.
  3476. --*/
  3477. {
  3478. LONG temp;
  3479. DebugTrace(+0, DEBUG_TRACE_LIP, "Burst failure, NpScb = %X\n", NpScb );
  3480. if ( NpScb->NwReceiveDelay != NpScb->CurrentBurstDelay ) {
  3481. //
  3482. // This burst has already failed
  3483. //
  3484. return;
  3485. }
  3486. NpScb->NwBadReceiveDelay = NpScb->NwReceiveDelay;
  3487. //
  3488. // Add to the Receive delay. Never let it go above 5000ms.
  3489. //
  3490. temp = NpScb->NwGoodReceiveDelay - NpScb->NwBadReceiveDelay;
  3491. if (temp >= 0) {
  3492. NpScb->NwReceiveDelay += temp + 2;
  3493. } else {
  3494. NpScb->NwReceiveDelay += -temp + 2;
  3495. }
  3496. if ( NpScb->NwReceiveDelay > NpScb->NwMaxReceiveDelay ) {
  3497. NpScb->NwReceiveDelay = MaxReceiveDelay;
  3498. //
  3499. // If we have slowed down a lot then it might be that the server or a
  3500. // bridge only has a small buffer on its NIC. If this is the case then
  3501. // rather than Receiveing a big burst with long even gaps between the
  3502. // packets, we should try to Receive a burst the size of the buffer.
  3503. //
  3504. if ( !DontShrink ) {
  3505. if (((NpScb->MaxReceiveSize - 1) / NpScb->MaxPacketSize) > 2 ) {
  3506. // Round down to the next packet
  3507. NpScb->MaxReceiveSize = ((NpScb->MaxReceiveSize - 1) / NpScb->MaxPacketSize) * NpScb->MaxPacketSize;
  3508. //
  3509. // Adjust ReceiveDelay below threshold to see if things improve before
  3510. // we shrink the size again.
  3511. //
  3512. NpScb->NwReceiveDelay = NpScb->NwGoodReceiveDelay = NpScb->NwBadReceiveDelay = MinReceiveDelay;
  3513. } else {
  3514. //
  3515. // We reached the minimum size with the maximum delay. Give up on burst.
  3516. //
  3517. NpScb->ReceiveBurstModeEnabled = FALSE;
  3518. }
  3519. }
  3520. }
  3521. NpScb->ReceiveBurstSuccessCount = 0;
  3522. DebugTrace( 0, DEBUG_TRACE_LIP, "New Receive Delay = %d\n", NpScb->NwReceiveDelay );
  3523. }
  3524. VOID
  3525. NwProcessSendBurstSuccess(
  3526. PNONPAGED_SCB NpScb
  3527. )
  3528. /*++
  3529. Routine Description:
  3530. This routine adjust burst parameters after a successful burst operation.
  3531. Arguments:
  3532. NpScb - A pointer to the SCB that has completed the burst.
  3533. Return Value:
  3534. None.
  3535. --*/
  3536. {
  3537. LONG temp;
  3538. DebugTrace( 0, DEBUG_TRACE_LIP, "Successful burst, NpScb = %X\n", NpScb );
  3539. if ( NpScb->NwSendDelay != NpScb->CurrentBurstDelay ) {
  3540. //
  3541. // This burst has already failed
  3542. //
  3543. return;
  3544. }
  3545. if ( NpScb->SendBurstSuccessCount > BurstSuccessCount ) {
  3546. if (NpScb->NwSendDelay != MinSendDelay ) {
  3547. NpScb->NwGoodSendDelay = NpScb->NwSendDelay;
  3548. temp = NpScb->NwGoodSendDelay - NpScb->NwBadSendDelay;
  3549. if (temp >= 0) {
  3550. NpScb->NwSendDelay -= 1 + temp;
  3551. } else {
  3552. NpScb->NwSendDelay -= 1 - temp;
  3553. }
  3554. if (NpScb->NwSendDelay < MinSendDelay ) {
  3555. NpScb->NwSendDelay = MinSendDelay;
  3556. }
  3557. NpScb->NtSendDelay.QuadPart = NpScb->NwSendDelay * -1000;
  3558. DebugTrace( 0, DEBUG_TRACE_LIP, "New Send Delay = %d\n", NpScb->NwSendDelay );
  3559. //
  3560. // Start monitoring success at the new rate.
  3561. //
  3562. NpScb->SendBurstSuccessCount = 0;
  3563. } else if ( NpScb->SendBurstSuccessCount > BurstSuccessCount2 ) {
  3564. //
  3565. // We may have had a really bad patch causing BadSendDelay to be very big.
  3566. // If we leave it at its current value then at the first sign of trouble
  3567. // we will make SendDelay very big
  3568. //
  3569. NpScb->NwGoodSendDelay = NpScb->NwBadSendDelay = NpScb->NwSendDelay;
  3570. //
  3571. // Is it time to increase the number of packets in the burst?
  3572. // AllowGrowth == 0 to be the same as the VLM client.
  3573. //
  3574. if (( AllowGrowth ) &&
  3575. ( NpScb->NwSendDelay <= MinSendDelay ) &&
  3576. ( NpScb->MaxSendSize < NwMaxSendSize)) {
  3577. NpScb->MaxSendSize += NpScb->MaxPacketSize;
  3578. if ( NpScb->MaxSendSize > NwMaxSendSize) {
  3579. NpScb->MaxSendSize = NwMaxSendSize;
  3580. }
  3581. }
  3582. NpScb->SendBurstSuccessCount = 0;
  3583. } else {
  3584. NpScb->SendBurstSuccessCount++;
  3585. }
  3586. } else {
  3587. NpScb->SendBurstSuccessCount++;
  3588. }
  3589. }
  3590. VOID
  3591. NwProcessReceiveBurstSuccess(
  3592. PNONPAGED_SCB NpScb
  3593. )
  3594. /*++
  3595. Routine Description:
  3596. This routine adjust burst parameters after a successful burst operation.
  3597. Arguments:
  3598. NpScb - A pointer to the SCB that has completed the burst.
  3599. Return Value:
  3600. None.
  3601. --*/
  3602. {
  3603. LONG temp;
  3604. DebugTrace( 0, DEBUG_TRACE_LIP, "Successful burst, NpScb = %X\n", NpScb );
  3605. if ( NpScb->NwReceiveDelay != NpScb->CurrentBurstDelay ) {
  3606. //
  3607. // This burst has already failed
  3608. //
  3609. return;
  3610. }
  3611. if ( NpScb->ReceiveBurstSuccessCount > BurstSuccessCount ) {
  3612. //
  3613. // Once the vlm client reaches the Maximum delay it does not
  3614. // shrink again.
  3615. //
  3616. if ( NpScb->NwReceiveDelay != MinReceiveDelay ) {
  3617. NpScb->NwGoodReceiveDelay = NpScb->NwReceiveDelay;
  3618. temp = NpScb->NwGoodReceiveDelay - NpScb->NwBadReceiveDelay;
  3619. if (temp >= 0) {
  3620. NpScb->NwReceiveDelay -= 1 + temp;
  3621. } else {
  3622. NpScb->NwReceiveDelay -= 1 - temp;
  3623. }
  3624. DebugTrace( 0, DEBUG_TRACE_LIP, "New Receive Delay = %d\n", NpScb->NwReceiveDelay );
  3625. if (NpScb->NwReceiveDelay < MinReceiveDelay ) {
  3626. NpScb->NwReceiveDelay = MinReceiveDelay;
  3627. }
  3628. //
  3629. // Start monitoring success at the new rate.
  3630. //
  3631. NpScb->ReceiveBurstSuccessCount = 0;
  3632. } else if ( NpScb->ReceiveBurstSuccessCount > BurstSuccessCount2 ) {
  3633. //
  3634. // We may have had a really bad patch causing BadReceiveDelay to be very big.
  3635. // If we leave it at its current value then at the first sign of trouble
  3636. // we will make ReceiveDelay very big
  3637. //
  3638. NpScb->NwGoodReceiveDelay = NpScb->NwBadReceiveDelay = NpScb->NwReceiveDelay;
  3639. //
  3640. // Is it time to increase the number of packets in the burst?
  3641. //
  3642. if (( AllowGrowth ) &&
  3643. ( NpScb->NwReceiveDelay <= MinReceiveDelay ) &&
  3644. ( NpScb->MaxReceiveSize < NwMaxReceiveSize)) {
  3645. NpScb->MaxReceiveSize += NpScb->MaxPacketSize;
  3646. if ( NpScb->MaxReceiveSize > NwMaxReceiveSize) {
  3647. NpScb->MaxReceiveSize = NwMaxReceiveSize;
  3648. }
  3649. }
  3650. NpScb->ReceiveBurstSuccessCount = 0;
  3651. } else {
  3652. NpScb->ReceiveBurstSuccessCount++;
  3653. }
  3654. } else {
  3655. NpScb->ReceiveBurstSuccessCount++;
  3656. }
  3657. }
  3658. VOID
  3659. NwProcessPositiveAck(
  3660. PNONPAGED_SCB NpScb
  3661. )
  3662. /*++
  3663. Routine Description:
  3664. This routine processes a positive acknowledgement.
  3665. Arguments:
  3666. NpScb - A pointer to the SCB that has experienced a burst failure.
  3667. Return Value:
  3668. None.
  3669. --*/
  3670. {
  3671. DebugTrace( 0, Dbg, "Positive ACK, NpScb = %X\n", NpScb );
  3672. //
  3673. // tommye MS 90541 / MCS 277
  3674. //
  3675. // Theory has it that we end up here about every half second,
  3676. // but I don't think we really know how long this packet has been
  3677. // outstanding. So, we'll just count this half-second event towards
  3678. // our timeout. Once this exceeds NwAbsoluteTotalWaitTime, then we
  3679. // won't reset the RetryCount and the DPC should handle it from there.
  3680. //
  3681. NpScb->TotalWaitTime++;
  3682. //
  3683. // If we have not waited longer than the absolute total, keep waiting.
  3684. // If we have waited too long, let ourselves timeout.
  3685. //
  3686. // If NwAbsoluteTotalWaitTime is 0, then we are prepared to wait forever.
  3687. //
  3688. if ( NpScb->TotalWaitTime < NwAbsoluteTotalWaitTime ||
  3689. NwAbsoluteTotalWaitTime == 0) {
  3690. NpScb->RetryCount = DefaultRetryCount;
  3691. } else {
  3692. DebugTrace( 0, Dbg, "Request exceeds absolute total wait time\n", 0 );
  3693. }
  3694. }