Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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