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

3741 lines
107 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. ipx.c
  5. Abstract:
  6. This module implements IPX transport handling for the server.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 28-Oct-1993
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "ipx.tmh"
  13. #pragma hdrstop
  14. #if SRVDBG_PERF
  15. BOOLEAN Trap512s = FALSE;
  16. BOOLEAN Break512s = FALSE;
  17. ULONG Trapped512s = 0;
  18. BOOLEAN UnlocksGoFast = TRUE;
  19. BOOLEAN OpensGoSlow = TRUE;
  20. BOOLEAN GlommingAllowed = TRUE;
  21. #endif
  22. #define NAME_CLAIM_ATTEMPTS 5
  23. #define NAME_CLAIM_INTERVAL 500 // milliseconds
  24. #define MPX_HEADER_SIZE (sizeof(SMB_HEADER) + sizeof(REQ_WRITE_MPX))
  25. PCONNECTION
  26. GetIpxConnection (
  27. IN PWORK_CONTEXT WorkContext,
  28. IN PENDPOINT Endpoint,
  29. IN PTDI_ADDRESS_IPX ClientAddress,
  30. IN PUCHAR ClientName
  31. );
  32. VOID
  33. PurgeIpxConnections (
  34. IN PENDPOINT Endpoint
  35. );
  36. NTSTATUS
  37. SendNameClaim (
  38. IN PENDPOINT Endpoint,
  39. IN PVOID ServerNetbiosName,
  40. IN PVOID DestinationNetbiosName,
  41. IN PTA_IPX_ADDRESS DestinationAddress,
  42. IN UCHAR NameClaimPacketType,
  43. IN USHORT ClientMessageId,
  44. IN UCHAR IpxPacketType,
  45. IN PIPX_DATAGRAM_OPTIONS DatagramOptions
  46. );
  47. VOID SRVFASTCALL
  48. IpxRestartNegotiate(
  49. IN OUT PWORK_CONTEXT WorkContext
  50. );
  51. VOID SRVFASTCALL
  52. IpxRestartReceive (
  53. IN OUT PWORK_CONTEXT WorkContext
  54. );
  55. VOID
  56. SrvFreeIpxConnectionInIndication(
  57. IN PWORK_CONTEXT WorkContext
  58. );
  59. VOID
  60. StartSendNoConnection (
  61. IN OUT PWORK_CONTEXT WorkContext,
  62. IN BOOLEAN UseNameSocket,
  63. IN BOOLEAN LocalTargetValid
  64. );
  65. VOID SRVFASTCALL
  66. SrvIpxFastRestartRead (
  67. IN OUT PWORK_CONTEXT WorkContext
  68. );
  69. BOOLEAN
  70. SetupIpxFastCoreRead (
  71. IN OUT PWORK_CONTEXT WorkContext
  72. );
  73. #ifdef ALLOC_PRAGMA
  74. #pragma alloc_text( PAGE, SrvIpxClaimServerName )
  75. #pragma alloc_text( PAGE, IpxRestartReceive )
  76. #pragma alloc_text( PAGE, SrvIpxFastRestartRead )
  77. #endif
  78. #if 0
  79. NOT PAGEABLE -- GetWorkItem
  80. NOT PAGEABLE -- SendNameClaim
  81. NOT PAGEABLE -- SrvIpxServerDatagramHandler
  82. NOT PAGEABLE -- SrvIpxNameDatagramHandler
  83. NOT PAGEABLE -- SrvIpxStartSend
  84. NOT PAGEABLE -- StartSendNoConnection
  85. NOT PAGEABLE -- RequeueIpxWorkItemAtSendCompletion
  86. NOT PAGEABLE -- PurgeIpxConnections
  87. NOT PAGEABLE -- IpxRestartNegotiate
  88. NOT PAGEABLE -- SetupIpxFastCoreRead
  89. NOT PAGEABLE -- SrvFreeIpxConnectionInIndication
  90. #endif
  91. NTSTATUS
  92. SendNameClaim (
  93. IN PENDPOINT Endpoint,
  94. IN PVOID ServerNetbiosName,
  95. IN PVOID DestinationNetbiosName,
  96. IN PTA_IPX_ADDRESS DestinationAddress,
  97. IN UCHAR NameClaimPacketType,
  98. IN USHORT MessageId,
  99. IN UCHAR IpxPacketType,
  100. IN PIPX_DATAGRAM_OPTIONS DatagramOptions
  101. )
  102. {
  103. PWORK_CONTEXT workContext;
  104. PSMB_IPX_NAME_PACKET buffer;
  105. PWORK_QUEUE queue = PROCESSOR_TO_QUEUE();
  106. //
  107. // Get a work item to use for the send.
  108. //
  109. ALLOCATE_WORK_CONTEXT( queue, &workContext );
  110. if ( workContext == NULL ) {
  111. //
  112. // We're out of WorkContext structures, and we aren't able to allocate
  113. // any more just now. Let's at least cause a worker thread to allocate some more
  114. // by incrementing the NeedWorkItem counter. This will cause the next
  115. // freed WorkContext structure to get dispatched to SrvServiceWorkItemShortage.
  116. // While SrvServiceWorkItemShortage probably won't find any work to do, it will
  117. // allocate more WorkContext structures if it can. Maybe this will help next time.
  118. //
  119. InterlockedIncrement( &queue->NeedWorkItem );
  120. return STATUS_INSUFFICIENT_RESOURCES;
  121. }
  122. //
  123. // Format the name claim packet.
  124. //
  125. buffer = (PSMB_IPX_NAME_PACKET)workContext->ResponseBuffer->Buffer;
  126. RtlZeroMemory( buffer->Route, sizeof(buffer->Route) );
  127. buffer->Operation = NameClaimPacketType;
  128. buffer->NameType = SMB_IPX_NAME_TYPE_MACHINE;
  129. buffer->MessageId = MessageId;
  130. RtlCopyMemory( buffer->Name, ServerNetbiosName, SMB_IPX_NAME_LENGTH );
  131. RtlCopyMemory( buffer->SourceName, DestinationNetbiosName, SMB_IPX_NAME_LENGTH );
  132. workContext->ResponseBuffer->DataLength = sizeof(SMB_IPX_NAME_PACKET);
  133. workContext->ResponseBuffer->Mdl->ByteCount = sizeof(SMB_IPX_NAME_PACKET);
  134. //
  135. // Format the destination address and send the packet.
  136. //
  137. workContext->Endpoint = Endpoint;
  138. DEBUG workContext->FsdRestartRoutine = NULL;
  139. workContext->ClientAddress->IpxAddress = *DestinationAddress;
  140. if ( ARGUMENT_PRESENT(DatagramOptions) ) {
  141. workContext->ClientAddress->DatagramOptions = *DatagramOptions;
  142. workContext->ClientAddress->DatagramOptions.PacketType = IpxPacketType;
  143. StartSendNoConnection( workContext, TRUE, TRUE );
  144. } else {
  145. workContext->ClientAddress->DatagramOptions.PacketType = IpxPacketType;
  146. StartSendNoConnection( workContext, TRUE, FALSE );
  147. }
  148. return STATUS_SUCCESS;
  149. } // SendNameClaim
  150. NTSTATUS
  151. SrvIpxClaimServerName (
  152. IN PENDPOINT Endpoint,
  153. IN PVOID NetbiosName
  154. )
  155. {
  156. NTSTATUS status;
  157. ULONG i;
  158. LARGE_INTEGER interval;
  159. TA_IPX_ADDRESS broadcastAddress;
  160. PAGED_CODE( );
  161. //
  162. // The destination of the name claim packet is the broadcast address.
  163. //
  164. broadcastAddress.TAAddressCount = 1;
  165. broadcastAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
  166. broadcastAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  167. broadcastAddress.Address[0].Address[0].NetworkAddress = 0;
  168. broadcastAddress.Address[0].Address[0].NodeAddress[0] = 0xff;
  169. broadcastAddress.Address[0].Address[0].NodeAddress[1] = 0xff;
  170. broadcastAddress.Address[0].Address[0].NodeAddress[2] = 0xff;
  171. broadcastAddress.Address[0].Address[0].NodeAddress[3] = 0xff;
  172. broadcastAddress.Address[0].Address[0].NodeAddress[4] = 0xff;
  173. broadcastAddress.Address[0].Address[0].NodeAddress[5] = 0xff;
  174. broadcastAddress.Address[0].Address[0].Socket = SMB_IPX_NAME_SOCKET;
  175. //
  176. // Send the name claim packet 5 times, waiting 1/2 second after
  177. // each send. If anyone else claims the name, fail.
  178. //
  179. interval.QuadPart = Int32x32To64( NAME_CLAIM_INTERVAL, -1*10*1000 );
  180. for ( i = 0; i < NAME_CLAIM_ATTEMPTS; i++ ) {
  181. //
  182. // Send the name claim.
  183. //
  184. status = SendNameClaim(
  185. Endpoint,
  186. NetbiosName,
  187. NetbiosName,
  188. &broadcastAddress,
  189. SMB_IPX_NAME_CLAIM,
  190. 0,
  191. 0x14,
  192. NULL
  193. );
  194. if ( !NT_SUCCESS(status) ) {
  195. return status;
  196. }
  197. //
  198. // Wait 1/2 second. If a response arrives, the datagram
  199. // handler marks the endpoint, and we quit.
  200. //
  201. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  202. if ( Endpoint->NameInConflict ) {
  203. return STATUS_DUPLICATE_NAME;
  204. }
  205. }
  206. //
  207. // We now own the name.
  208. //
  209. return STATUS_SUCCESS;
  210. } // SrvIpxClaimServerName
  211. NTSTATUS
  212. SrvIpxNameDatagramHandler (
  213. IN PVOID TdiEventContext,
  214. IN int SourceAddressLength,
  215. IN PVOID SourceAddress,
  216. IN int OptionsLength,
  217. IN PVOID Options,
  218. IN ULONG ReceiveDatagramFlags,
  219. IN ULONG BytesIndicated,
  220. IN ULONG BytesAvailable,
  221. OUT ULONG *BytesTaken,
  222. IN PVOID Tsdu,
  223. OUT PIRP *IoRequestPacket
  224. )
  225. /*++
  226. Routine Description:
  227. This is the receive datagram event handler for the IPX NetBIOS name
  228. socket.
  229. Arguments:
  230. TdiEventContext - Pointer to receiving endpoint
  231. SourceAddressLength - Length of SourceAddress
  232. SourceAddress - Address of sender
  233. OptionsLength - Length of options
  234. Options - Options for the receive
  235. ReceiveDatagramFlags - Set of flags indicating the status of the
  236. received message
  237. BytesIndicated - Number of bytes in this indication (lookahead)
  238. BytesAvailable - Number of bytes in the complete TSDU
  239. BytesTaken - Returns the number of bytes taken by the handler
  240. Tsdu - Pointer to the Transport Service Data Unit
  241. IoRequestPacket - Returns a pointer to I/O request packet, if the
  242. returned status is STATUS_MORE_PROCESSING_REQUIRED. This IRP is
  243. made the 'current' Receive for the endpoint.
  244. Return Value:
  245. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  246. processed the request. If STATUS_MORE_PROCESSING_REQUIRED,
  247. the Irp parameter points to a formatted Receive request to
  248. be used to receive the data. If STATUS_DATA_NOT_ACCEPTED,
  249. the message is lost.
  250. --*/
  251. {
  252. PENDPOINT endpoint = (PENDPOINT)TdiEventContext;
  253. PSMB_IPX_NAME_PACKET packet;
  254. //
  255. // We have received a name query or claim request. Is it for us?
  256. //
  257. if( BytesIndicated < sizeof( SMB_IPX_NAME_PACKET ) ) {
  258. IF_DEBUG( IPXNAMECLAIM ) {
  259. KdPrint(("NameDatagramHandler: Short packet %u bytes\n", BytesIndicated ));
  260. }
  261. return( STATUS_SUCCESS );
  262. }
  263. packet = (PSMB_IPX_NAME_PACKET)Tsdu;
  264. IF_DEBUG(IPXNAMECLAIM) {
  265. STRING string, srcString;
  266. string.Buffer = (PSZ)packet->Name;
  267. string.Length = SMB_IPX_NAME_LENGTH;
  268. srcString.Buffer = (PSZ)packet->SourceName;
  269. srcString.Length = SMB_IPX_NAME_LENGTH;
  270. KdPrint(( "NameDatagramHandler: type: %x, name %z, from %z\n",
  271. packet->Operation, (PCSTRING)&string, (PCSTRING)&srcString ));
  272. }
  273. if ( SourceAddressLength < sizeof(IPX_ADDRESS_EXTENDED_FLAGS) ) {
  274. IF_DEBUG(IPXNAMECLAIM) {
  275. KdPrint(( "SourceAddress too short. Expecting %d got %d\n",
  276. sizeof(IPX_ADDRESS_EXTENDED_FLAGS), SourceAddressLength ));
  277. }
  278. return(STATUS_SUCCESS);
  279. }
  280. if ( !RtlEqualMemory(
  281. packet->Name,
  282. endpoint->TransportAddress.Buffer,
  283. SMB_IPX_NAME_LENGTH) ) {
  284. IF_DEBUG(IPXNAMECLAIM) KdPrint(( " not for us\n" ));
  285. return STATUS_SUCCESS;
  286. }
  287. //
  288. // The packet is for our name. If we sent it, ignore it.
  289. //
  290. if ( RtlEqualMemory(
  291. &endpoint->LocalAddress,
  292. &((PTA_IPX_ADDRESS)SourceAddress)->Address[0].Address[0],
  293. sizeof(TDI_ADDRESS_IPX) ) ) {
  294. IF_DEBUG(IPXNAMECLAIM) KdPrint(( " we sent it!\n" ));
  295. return STATUS_SUCCESS;
  296. }
  297. //
  298. // If it's a query or a claim, send a response. If it's a 'name
  299. // recognized' packet, then another server owns our name.
  300. //
  301. if ( packet->Operation == SMB_IPX_NAME_FOUND ) {
  302. //
  303. // Did we send this ?
  304. //
  305. if ( (((PIPX_ADDRESS_EXTENDED_FLAGS)SourceAddress)->Flags &
  306. IPX_EXTENDED_FLAG_LOCAL) == 0 ) {
  307. //
  308. // This came from another station.
  309. //
  310. IF_DEBUG(IPXNAMECLAIM) KdPrint(( " name in conflict!\n" ));
  311. endpoint->NameInConflict = TRUE;
  312. }
  313. } else {
  314. //
  315. // This is a name query. If bit 0x8000 is set, this is from a
  316. // redir that supports named pipes correctly.
  317. //
  318. if ( !SrvEnableWfW311DirectIpx &&
  319. ((packet->MessageId & 0x8000) == 0)) {
  320. IF_DEBUG(IPXNAMECLAIM) KdPrint(( " msg ID high bit not set.\n" ));
  321. return STATUS_SUCCESS;
  322. }
  323. IF_DEBUG(IPXNAMECLAIM) KdPrint(( " sending name recognized response!\n" ));
  324. SendNameClaim(
  325. endpoint,
  326. endpoint->TransportAddress.Buffer,
  327. packet->SourceName,
  328. (PTA_IPX_ADDRESS)SourceAddress,
  329. SMB_IPX_NAME_FOUND,
  330. packet->MessageId,
  331. 0x04,
  332. (PIPX_DATAGRAM_OPTIONS)Options
  333. );
  334. }
  335. return STATUS_SUCCESS;
  336. } // SrvIpxNameDatagramHandler
  337. NTSTATUS
  338. SrvIpxServerDatagramHandlerCommon (
  339. IN PVOID TdiEventContext,
  340. IN int SourceAddressLength,
  341. IN PVOID SourceAddress,
  342. IN int OptionsLength,
  343. IN PVOID Options,
  344. IN ULONG ReceiveDatagramFlags,
  345. IN ULONG BytesIndicated,
  346. IN ULONG BytesAvailable,
  347. OUT ULONG *BytesTaken,
  348. IN PVOID Tsdu,
  349. OUT PIRP *IoRequestPacket,
  350. IN PVOID TransportContext
  351. )
  352. /*++
  353. Routine Description:
  354. This is the receive datagram event handler for the IPX server socket.
  355. It attempts to dequeue a preformatted work item from a list
  356. anchored in the device object. If this is successful, it returns
  357. the IRP associated with the work item to the transport provider to
  358. be used to receive the data. Otherwise, the message is dropped.
  359. Arguments:
  360. TdiEventContext - Pointer to receiving endpoint
  361. SourceAddressLength - Length of SourceAddress
  362. SourceAddress - Address of sender
  363. OptionsLength - Length of options
  364. Options - Options for the receive
  365. ReceiveDatagramFlags - Set of flags indicating the status of the
  366. received message
  367. BytesIndicated - Number of bytes in this indication (lookahead)
  368. BytesAvailable - Number of bytes in the complete TSDU
  369. BytesTaken - Returns the number of bytes taken by the handler
  370. Tsdu - Pointer to buffer describing the Transport Service Data Unit
  371. IoRequestPacket - Returns a pointer to I/O request packet, if the
  372. returned status is STATUS_MORE_PROCESSING_REQUIRED. This IRP is
  373. made the 'current' Receive for the endpoint.
  374. TransportContext - NULL is this is not a chained receive, otherwise this
  375. is the pointer to the TransportContext when returning the NDIS buffer.
  376. Return Value:
  377. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  378. processed the request. If STATUS_MORE_PROCESSING_REQUIRED,
  379. the Irp parameter points to a formatted Receive request to
  380. be used to receive the data. If STATUS_DATA_NOT_ACCEPTED,
  381. the message is lost. If STATUS_PENDING, then TransportContext
  382. was not NULL and we decided that we are going to keep the NDIS
  383. buffer and return it later.
  384. --*/
  385. {
  386. PLIST_ENTRY listEntry;
  387. PWORK_CONTEXT workContext;
  388. PENDPOINT endpoint;
  389. USHORT sid;
  390. USHORT idIndex;
  391. USHORT sequenceNumber;
  392. USHORT nextSequenceNumber;
  393. USHORT mid;
  394. PCONNECTION connection;
  395. PNT_SMB_HEADER header;
  396. PSMB_PARAMS params;
  397. ULONG length;
  398. PTABLE_HEADER tableHeader;
  399. BOOLEAN resend;
  400. BOOLEAN firstPacketOfGlom = FALSE;
  401. PIRP irp;
  402. PIO_STACK_LOCATION irpSp;
  403. USHORT error;
  404. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  405. PBUFFER requestBuffer;
  406. PWORK_QUEUE workQueue;
  407. PREQ_WRITE_MPX request;
  408. USHORT fid;
  409. PRFCB rfcb;
  410. PWRITE_MPX_CONTEXT writeMpx;
  411. USHORT index;
  412. KIRQL oldIrql;
  413. NTSTATUS status = STATUS_SUCCESS;
  414. #if DBG
  415. workQueue = NULL;
  416. workContext = NULL;
  417. connection = NULL;
  418. if ( TransportContext ) {
  419. ASSERT( BytesAvailable == BytesIndicated );
  420. }
  421. #endif
  422. //
  423. // Make sure we've received a complete SMB
  424. //
  425. if( BytesIndicated < sizeof( SMB_HEADER ) + sizeof( USHORT ) ) {
  426. //
  427. // Short SMB. Eat it.
  428. //
  429. return STATUS_SUCCESS;
  430. }
  431. //
  432. // Pull out stuff we'll need later..
  433. //
  434. endpoint = (PENDPOINT)TdiEventContext;
  435. header = (PNT_SMB_HEADER)Tsdu;
  436. sid = SmbGetUshort( &header->Sid );
  437. sequenceNumber = SmbGetUshort( &header->SequenceNumber );
  438. ASSERT( *(PUCHAR)header == 0xff ); // Must be 0xff'SMB'
  439. ASSERT( endpoint != NULL );
  440. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  441. if ( sid == 0 ) {
  442. //
  443. // Must be a negotiate
  444. //
  445. if( header->Command != SMB_COM_NEGOTIATE ||
  446. GET_BLOCK_STATE( endpoint ) != BlockStateActive ) {
  447. KeLowerIrql( oldIrql );
  448. return STATUS_SUCCESS;
  449. }
  450. //
  451. // Do not accept new clients until the server has completed
  452. // registering for PNP notifications
  453. //
  454. if( SrvCompletedPNPRegistration == FALSE ) {
  455. KeLowerIrql( oldIrql );
  456. return STATUS_SUCCESS;
  457. }
  458. //
  459. // Queue this to the fsp.
  460. //
  461. //
  462. // Save the sender's IPX address.
  463. //
  464. workQueue = PROCESSOR_TO_QUEUE();
  465. ALLOCATE_WORK_CONTEXT( workQueue, &workContext );
  466. if( workContext != NULL ) {
  467. workContext->ClientAddress->IpxAddress =
  468. *(PTA_IPX_ADDRESS)SourceAddress;
  469. workContext->ClientAddress->DatagramOptions =
  470. *(PIPX_DATAGRAM_OPTIONS)Options;
  471. irp = workContext->Irp;
  472. workContext->Endpoint = endpoint;
  473. workContext->QueueToHead = TRUE;
  474. workContext->FspRestartRoutine = IpxRestartNegotiate;
  475. if ( BytesAvailable == BytesIndicated ) {
  476. TdiCopyLookaheadData(
  477. workContext->RequestBuffer->Buffer,
  478. Tsdu,
  479. BytesIndicated,
  480. ReceiveDatagramFlags
  481. );
  482. workContext->RequestBuffer->DataLength = BytesIndicated;
  483. *BytesTaken = BytesAvailable;
  484. goto queue_to_fsp;
  485. } else {
  486. workContext->FsdRestartRoutine = SrvQueueWorkToFsp;
  487. goto build_irp;
  488. }
  489. }
  490. //
  491. // Could not allocate a work context!
  492. //
  493. KeLowerIrql( oldIrql );
  494. InterlockedIncrement( &workQueue->NeedWorkItem );
  495. return STATUS_SUCCESS;
  496. }
  497. //
  498. // Not a Negotiate, and non-zero SID.
  499. // Check if the connection is cached.
  500. //
  501. idIndex = IPXSID_INDEX( sid );
  502. ACQUIRE_DPC_SPIN_LOCK(
  503. &ENDPOINT_SPIN_LOCK(idIndex & ENDPOINT_LOCK_MASK) );
  504. tableHeader = &endpoint->ConnectionTable;
  505. if ( (idIndex >= (USHORT)tableHeader->TableSize) ||
  506. ((connection = tableHeader->Table[idIndex].Owner) == NULL) ||
  507. (connection->Sid != sid) ||
  508. (GET_BLOCK_STATE(connection) != BlockStateActive) ) {
  509. IF_DEBUG(IPX2) {
  510. KdPrint(( "Bad Sid: " ));
  511. if ( idIndex >= (USHORT)tableHeader->TableSize ) {
  512. KdPrint(( "Index >= tableSize (index %d, size %d)\n",
  513. idIndex, (USHORT)tableHeader->TableSize ));
  514. } else if( tableHeader->Table[ idIndex ].Owner == NULL ) {
  515. KdPrint(( "Owner == NULL\n" ));
  516. } else if( connection->Sid != sid ) {
  517. KdPrint(( "connection->Sid = %X, sid = %X\n", connection->Sid, sid ));
  518. } else {
  519. KdPrint(( "Connection blk state %X\n", GET_BLOCK_STATE( connection ) ));
  520. }
  521. }
  522. workQueue = PROCESSOR_TO_QUEUE();
  523. //
  524. // We have an invalid SID. It would be nice to silently fail it,
  525. // but that causes auto-reconnect on clients take an unnecessarily
  526. // long time.
  527. //
  528. RELEASE_DPC_SPIN_LOCK( &
  529. ENDPOINT_SPIN_LOCK(idIndex & ENDPOINT_LOCK_MASK) );
  530. ALLOCATE_WORK_CONTEXT( workQueue, &workContext );
  531. if( workContext != NULL ) {
  532. error = SMB_ERR_BAD_SID;
  533. resend = FALSE;
  534. goto respond;
  535. }
  536. //
  537. // Unable to allocate workitem, give up
  538. //
  539. KeLowerIrql( oldIrql );
  540. InterlockedIncrement( &workQueue->NeedWorkItem );
  541. return STATUS_SUCCESS;
  542. }
  543. #if MULTIPROCESSOR
  544. //
  545. // See if it's time to home this connection to another processor
  546. //
  547. if( --(connection->BalanceCount) == 0 ) {
  548. SrvBalanceLoad( connection );
  549. }
  550. workQueue = connection->CurrentWorkQueue;
  551. #else
  552. workQueue = &SrvWorkQueues[0];
  553. #endif
  554. //
  555. // The connection is active. Record the time that this request
  556. // arrived. If the sequence numbers match, handle this as a lost
  557. // response.
  558. //
  559. nextSequenceNumber = connection->SequenceNumber;
  560. GET_SERVER_TIME( workQueue, &connection->LastRequestTime );
  561. //
  562. // If this is a sequenced SMB, it has to have the right sequence
  563. // number: one greater than the current sequence number (but not 0).
  564. //
  565. if ( sequenceNumber != 0 ) {
  566. if ( nextSequenceNumber != 0 ) {
  567. ULONG tmpNext = nextSequenceNumber;
  568. if ( ++nextSequenceNumber == 0 ) nextSequenceNumber++;
  569. if ( sequenceNumber != nextSequenceNumber ) {
  570. if ( sequenceNumber == tmpNext ) {
  571. goto duplicate_request;
  572. }
  573. //
  574. // Bad sequence number. Ignore this message.
  575. //
  576. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Bad sequence number; ignoring\n" ));
  577. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  578. KeLowerIrql( oldIrql );
  579. return STATUS_SUCCESS;
  580. }
  581. }
  582. //
  583. // The sequence number is correct. Update the connection's sequence number and
  584. // indicate that we're processing this message. (We need to
  585. // allocate the work item first because we're modifying
  586. // connection state.) Then go receive the message.
  587. //
  588. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  589. if( workContext != NULL ) {
  590. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Receiving sequenced request %x\n", sequenceNumber ));
  591. connection->SequenceNumber = sequenceNumber;
  592. connection->LastResponseLength = (USHORT)-1;
  593. connection->IpxDuplicateCount = 0;
  594. if ( header->Command == SMB_COM_WRITE_MPX ) {
  595. goto process_writempx;
  596. } else {
  597. goto process_not_writempx;
  598. }
  599. }
  600. //
  601. // Unable to allocate workitem, give up
  602. //
  603. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  604. KeLowerIrql( oldIrql );
  605. InterlockedIncrement( &connection->CurrentWorkQueue->NeedWorkItem );
  606. return STATUS_SUCCESS;
  607. }
  608. //
  609. // Unsequenced SMB. Check to see if it's being processed or is in
  610. // the queue to be processed. If it's not, then we can process this
  611. // message.
  612. //
  613. // *** We don't do this check for write MPX because the multiple SMBs
  614. // in a write MPX all have the same MID.
  615. //
  616. if ( header->Command != SMB_COM_WRITE_MPX ) {
  617. mid = SmbGetUshort( &header->Mid ); // NOT Aligned
  618. //
  619. // We need to receive this message. Get a work item.
  620. //
  621. IF_DEBUG(IPX) {
  622. KdPrint(( "SRVIPX: Receiving unsequenced request mid=%x\n",
  623. SmbGetUshort(&header->Mid) )); // NOT Aligned
  624. }
  625. for ( listEntry = connection->InProgressWorkItemList.Flink;
  626. listEntry != &connection->InProgressWorkItemList;
  627. listEntry = listEntry->Flink ) {
  628. PWORK_CONTEXT tmpWorkContext;
  629. tmpWorkContext = CONTAINING_RECORD(
  630. listEntry,
  631. WORK_CONTEXT,
  632. InProgressListEntry );
  633. if ( SmbGetAlignedUshort(&tmpWorkContext->RequestHeader->Mid) == mid ) {
  634. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Duplicate (queued) unsequenced request mid=%x\n", mid ));
  635. if( connection->IpxDuplicateCount++ < connection->IpxDropDuplicateCount ) {
  636. //
  637. // We drop every few duplicate requests from the client
  638. //
  639. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  640. KeLowerIrql( oldIrql );
  641. return STATUS_SUCCESS;
  642. }
  643. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  644. error = SMB_ERR_WORKING;
  645. resend = FALSE;
  646. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  647. if( workContext != NULL ) {
  648. connection->IpxDuplicateCount = 0;
  649. goto respond;
  650. }
  651. //
  652. // Unable to allocate workitem, give up
  653. //
  654. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  655. KeLowerIrql( oldIrql );
  656. InterlockedIncrement( &connection->CurrentWorkQueue->NeedWorkItem );
  657. return STATUS_SUCCESS;
  658. }
  659. }
  660. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  661. if( workContext != NULL ) {
  662. goto process_not_writempx;
  663. }
  664. //
  665. // Unable to allocate workitem, give up
  666. //
  667. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  668. KeLowerIrql( oldIrql );
  669. InterlockedIncrement( &connection->CurrentWorkQueue->NeedWorkItem );
  670. return STATUS_SUCCESS;
  671. }
  672. ASSERT( workContext == NULL );
  673. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  674. if( workContext == NULL ) {
  675. //
  676. // Unable to allocate workitem, give up
  677. //
  678. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  679. KeLowerIrql( oldIrql );
  680. InterlockedIncrement( &connection->CurrentWorkQueue->NeedWorkItem );
  681. return STATUS_SUCCESS;
  682. }
  683. connection->IpxDuplicateCount = 0;
  684. process_writempx:
  685. //
  686. // Have we received enough of the message to interpret the request?
  687. //
  688. if( BytesIndicated < sizeof( SMB_HEADER ) + FIELD_OFFSET( REQ_WRITE_MPX, Buffer ) ) {
  689. //
  690. // Drop this fellow on the floor
  691. //
  692. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  693. KeLowerIrql( oldIrql );
  694. return STATUS_SUCCESS;
  695. }
  696. //
  697. // Reference the connection so we can release the lock.
  698. //
  699. ASSERT( connection != NULL );
  700. ASSERT( workContext != NULL );
  701. SrvReferenceConnectionLocked( connection );
  702. workContext->Connection = connection;
  703. workContext->Parameters.WriteMpx.TransportContext = NULL;
  704. //
  705. // Put the work item on the in-progress list.
  706. //
  707. SrvInsertTailList(
  708. &connection->InProgressWorkItemList,
  709. &workContext->InProgressListEntry
  710. );
  711. connection->InProgressWorkContextCount++;
  712. //
  713. // The sequence number is correct. Ensure that a work item is
  714. // available, then update the connection's sequence number and
  715. // indicate that we're processing this message. (We need to
  716. // allocate the work item first because we're modifying
  717. // connection state.) Then go receive the message.
  718. //
  719. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  720. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  721. //
  722. // This is a Write Mpx request, we need to save some state, in
  723. // order to prevent unnecessary out-of-order completion of the
  724. // sequenced part of a Write Mpx, which would lead to unnecessary
  725. // retransmissions.
  726. //
  727. //
  728. // Find the RFCB associated with this request.
  729. //
  730. // *** The following is adapted from SrvVerifyFid2.
  731. //
  732. request = (PREQ_WRITE_MPX)(header + 1);
  733. fid = SmbGetUshort( &request->Fid );
  734. //
  735. // See if this is the cached rfcb.
  736. //
  737. if ( connection->CachedFid == fid ) {
  738. rfcb = connection->CachedRfcb;
  739. } else {
  740. //
  741. // Verify that the FID is in range, is in use, and has the
  742. // correct sequence number.
  743. //
  744. index = FID_INDEX( fid );
  745. tableHeader = &connection->FileTable;
  746. if ( (index >= (USHORT)tableHeader->TableSize) ||
  747. ((rfcb = tableHeader->Table[index].Owner) == NULL) ||
  748. (rfcb->Fid != fid) ) {
  749. error = ERROR_INVALID_HANDLE;
  750. goto bad_fid;
  751. }
  752. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  753. error = ERROR_INVALID_HANDLE;
  754. goto bad_fid;
  755. }
  756. //
  757. // Cache the FID.
  758. //
  759. connection->CachedRfcb = rfcb;
  760. connection->CachedFid = (ULONG)fid;
  761. //
  762. // If there is a write behind error, return the error to the
  763. // client.
  764. //
  765. // !!! For now, we ignore write behind errors. Need to
  766. // figure out how to translate the saved NT status to a
  767. // DOS status...
  768. //
  769. #if 0
  770. if ( !NT_SUCCESS(rfcb->SavedError) ) {
  771. status = rfcb->SavedError;
  772. rfcb->SavedError = STATUS_SUCCESS;
  773. goto bad_fid;
  774. }
  775. #endif
  776. //
  777. // The FID is valid within the context of this connection.
  778. // Verify that the owning tree connect's TID is correct.
  779. //
  780. if ( (rfcb->Tid != SmbGetUshort(&header->Tid)) ||
  781. (rfcb->Uid != SmbGetUshort(&header->Uid)) ) {
  782. error = ERROR_INVALID_HANDLE;
  783. goto bad_fid;
  784. }
  785. }
  786. //
  787. // Mark the rfcb as active
  788. //
  789. rfcb->IsActive = TRUE;
  790. //
  791. // Since we don't support raw writes on IPX, there had
  792. // better not be one active.
  793. //
  794. ASSERT( rfcb->RawWriteCount == 0 );
  795. //
  796. // If the MID in the this packet is the same as the MID we're
  797. // currently working on, we can accept it.
  798. //
  799. writeMpx = &rfcb->WriteMpx;
  800. mid = SmbGetUshort( &header->Mid ); // NOT Aligned
  801. if ( mid == writeMpx->Mid ) {
  802. goto mpx_mid_ok;
  803. }
  804. //
  805. // If this a stale packet, ignore it. Stale here means that the
  806. // MID of the packet is equal to the MID of the previous write
  807. // mux. Such a packet can be received if a duplicate packet
  808. // from a previous write mux is delivered after a new write mux
  809. // starts.
  810. //
  811. // If this packet is for a new MID, but we're in the middle of
  812. // processing the current MID, then something is wrong -- the redir
  813. // should not send a new MID until we've replied to the old MID.
  814. // Ignore this packet.
  815. //
  816. if ( (mid == writeMpx->PreviousMid) || writeMpx->ReferenceCount ) {
  817. goto stale_mid;
  818. }
  819. //
  820. // It's not the MID we're currently working on, and it's not the
  821. // previous MID, and we're not glomming the current MID. So we
  822. // have to assume it's a new MID. If it's the first packet of a
  823. // write, we can prepare to glom.
  824. //
  825. // !!! This is a problem if we receive a delayed packet that is
  826. // the first packet of a MID older than the last MID. We
  827. // will then put the file into glom mode for that old MID,
  828. // will never be able to make progress on that file.
  829. //
  830. // !!! The mask == 1 test is not perfect. It depends on the
  831. // client using 1 in the first packet, which is not
  832. // guaranteed by the protocol.
  833. //
  834. writeMpx->PreviousMid = writeMpx->Mid;
  835. writeMpx->Mid = mid;
  836. #if SRVDBG_PERF
  837. if( GlommingAllowed )
  838. #endif
  839. if ( (SmbGetUlong( &request->Mask ) == 1) && writeMpx->MpxGlommingAllowed ) {
  840. writeMpx->GlomPending = TRUE;
  841. firstPacketOfGlom = TRUE;
  842. }
  843. mpx_mid_ok:
  844. //
  845. // Save the sender's IPX address.
  846. //
  847. workContext->Endpoint = endpoint;
  848. workContext->ClientAddress->IpxAddress = *(PTA_IPX_ADDRESS)SourceAddress;
  849. workContext->ClientAddress->DatagramOptions =
  850. *(PIPX_DATAGRAM_OPTIONS)Options;
  851. //
  852. // Bump the Write Mpx reference count in the RFCB.
  853. //
  854. writeMpx->ReferenceCount++;
  855. //
  856. // See if we can do indication time write glomming.
  857. // We will try this if:
  858. // we are in the middle of write glomming and
  859. // smb is valid and
  860. // we receive all the data
  861. //
  862. if ( writeMpx->Glomming &&
  863. ( BytesIndicated == BytesAvailable ) ) {
  864. UCHAR wordCount;
  865. USHORT byteCount;
  866. PSMB_USHORT byteCountPtr;
  867. ULONG availableSpaceForSmb;
  868. header = (PNT_SMB_HEADER) Tsdu;
  869. params = (PVOID)(header + 1);
  870. wordCount = *((PUCHAR)params);
  871. byteCountPtr = (PSMB_USHORT)( (PCHAR)params +
  872. sizeof(UCHAR) + (12 * sizeof(USHORT)) );
  873. byteCount =
  874. SmbGetUshort( (PSMB_USHORT)( (PCHAR)params +
  875. sizeof(UCHAR) + (12 * sizeof(USHORT))) );
  876. availableSpaceForSmb = BytesIndicated - sizeof(SMB_HEADER);
  877. //
  878. // Validate the WriteMpx smb.
  879. //
  880. if ( (SmbGetUlong((PULONG)header->Protocol) == SMB_HEADER_PROTOCOL)
  881. &&
  882. ((CHAR)wordCount == 12)
  883. &&
  884. ((PCHAR)byteCountPtr <= (PCHAR)header + BytesIndicated -
  885. sizeof(USHORT))
  886. &&
  887. ((12*sizeof(USHORT) + sizeof(UCHAR) + sizeof(USHORT) +
  888. byteCount) <= availableSpaceForSmb) ) {
  889. //
  890. // The connection SpinLock is released in this routine.
  891. //
  892. if ( AddPacketToGlomInIndication(
  893. workContext,
  894. rfcb,
  895. Tsdu,
  896. BytesAvailable,
  897. ReceiveDatagramFlags,
  898. SourceAddress,
  899. Options
  900. ) ) {
  901. //
  902. // We need to clean up the connection.
  903. //
  904. goto return_connection;
  905. }
  906. KeLowerIrql( oldIrql );
  907. return(STATUS_SUCCESS);
  908. }
  909. }
  910. //
  911. // The file is active and the TID is valid. Reference the
  912. // RFCB.
  913. //
  914. rfcb->BlockHeader.ReferenceCount++;
  915. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  916. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  917. workContext->Parameters.WriteMpx.FirstPacketOfGlom = firstPacketOfGlom;
  918. //
  919. // Save the RFCB address in the work context block.
  920. //
  921. ASSERT( workContext->Rfcb == NULL );
  922. workContext->Rfcb = rfcb;
  923. //
  924. // Change the FSP restart routine for the work item to one
  925. // that's specific to Write Mpx. This is necessary in order
  926. // to do proper cleanup if a receive error occurs.
  927. //
  928. workContext->FspRestartRoutine = SrvRestartReceiveWriteMpx;
  929. goto start_receive;
  930. process_not_writempx:
  931. //
  932. // Reference the connection and save a pointer to it in the work
  933. // item.
  934. //
  935. ASSERT( connection != NULL );
  936. ASSERT( workContext != NULL );
  937. ASSERT( workContext->FsdRestartRoutine == SrvQueueWorkToFspAtDpcLevel );
  938. SrvReferenceConnectionLocked( connection );
  939. //
  940. // Put the work item on the in-progress list.
  941. //
  942. SrvInsertTailList(
  943. &connection->InProgressWorkItemList,
  944. &workContext->InProgressListEntry
  945. );
  946. connection->InProgressWorkContextCount++;
  947. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  948. //
  949. // Save the sender's IPX address.
  950. //
  951. workContext->Connection = connection;
  952. workContext->Endpoint = endpoint;
  953. workContext->ClientAddress->IpxAddress = *(PTA_IPX_ADDRESS)SourceAddress;
  954. workContext->ClientAddress->DatagramOptions =
  955. *(PIPX_DATAGRAM_OPTIONS)Options;
  956. if ( header->Command == SMB_COM_LOCKING_ANDX ) {
  957. //
  958. // If this is a Locking&X SMB that includes at least one unlock
  959. // request, we want to process the request quickly. So we put
  960. // it at the head of the work queue.
  961. //
  962. PREQ_LOCKING_ANDX lockRequest = (PREQ_LOCKING_ANDX)(header + 1);
  963. #if SRVDBG_PERF
  964. if( UnlocksGoFast )
  965. #endif
  966. if( (PCHAR)header + BytesIndicated >= (PCHAR)(&lockRequest->ByteCount) &&
  967. SmbGetUshort(&lockRequest->NumberOfUnlocks) != 0 ) {
  968. workContext->QueueToHead = TRUE;
  969. }
  970. } else if ( (header->Command == SMB_COM_READ) &&
  971. (BytesIndicated == BytesAvailable) ) {
  972. //
  973. // Copy the indicated data.
  974. //
  975. TdiCopyLookaheadData(
  976. workContext->RequestBuffer->Buffer,
  977. Tsdu,
  978. BytesIndicated,
  979. ReceiveDatagramFlags
  980. );
  981. workContext->RequestBuffer->DataLength = BytesIndicated;
  982. //
  983. // See if we are all set to do the fast path.
  984. //
  985. if ( SetupIpxFastCoreRead( workContext ) ) {
  986. workContext->FspRestartRoutine = SrvIpxFastRestartRead;
  987. workContext->ProcessingCount++;
  988. workQueue->stats.BytesReceived += BytesIndicated;
  989. //
  990. // Insert the work item at the tail of the nonblocking
  991. // work queue.
  992. //
  993. SrvInsertWorkQueueTail(
  994. workQueue,
  995. (PQUEUEABLE_BLOCK_HEADER)workContext
  996. );
  997. KeLowerIrql( oldIrql );
  998. return STATUS_SUCCESS;
  999. }
  1000. irp = workContext->Irp;
  1001. goto queue_to_fsp;
  1002. } else if ( (header->Command == SMB_COM_OPEN_ANDX) ||
  1003. (header->Command == SMB_COM_NT_CREATE_ANDX) ) {
  1004. //
  1005. // If this is an attempt to open a file, route the
  1006. // request to a blocking worker thread. This keeps opens
  1007. // out of the way of handle-based operations.
  1008. //
  1009. #if SRVDBG_PERF
  1010. if( OpensGoSlow )
  1011. #endif
  1012. {
  1013. workContext->FsdRestartRoutine = SrvQueueWorkToBlockingThread;
  1014. workQueue = GET_BLOCKING_WORK_QUEUE();
  1015. }
  1016. } else if ( (header->Command == SMB_COM_CLOSE) ||
  1017. (header->Command == SMB_COM_FIND_CLOSE) ||
  1018. (header->Command == SMB_COM_FIND_CLOSE2) ) {
  1019. //
  1020. // Closing things is an operation that (1) releases resources, (2) is usually
  1021. // fast, and (3) can't be repeated indefinately by the client. Give the client
  1022. // a reward by putting it at the head of the queue.
  1023. //
  1024. workContext->QueueToHead = TRUE;
  1025. }
  1026. start_receive:
  1027. //
  1028. // If the SMB is completely within the indicated data, copy it
  1029. // directly into the buffer, avoiding the overhead of passing an IRP
  1030. // down to the transport.
  1031. //
  1032. irp = workContext->Irp;
  1033. if ( BytesIndicated == BytesAvailable ) {
  1034. //
  1035. // If this is a WRITE_MPX, and the buffer is big (how big is BIG?)
  1036. // and there is a TransportContext (indicating that we can take the
  1037. // NDIS buffer, then don't copy the data - just save the buffer
  1038. // address, length and transport context.
  1039. //
  1040. if ( BytesIndicated > SrvMaxCopyLength &&
  1041. header->Command == SMB_COM_WRITE_MPX &&
  1042. TransportContext ) {
  1043. workContext->Parameters.WriteMpx.Buffer = Tsdu;
  1044. workContext->Parameters.WriteMpx.ReceiveDatagramFlags =
  1045. ReceiveDatagramFlags;
  1046. workContext->Parameters.WriteMpx.TransportContext = TransportContext;
  1047. DEBUG *BytesTaken = BytesIndicated;
  1048. ASSERT( BytesIndicated >= MPX_HEADER_SIZE );
  1049. TdiCopyLookaheadData(
  1050. workContext->RequestBuffer->Buffer,
  1051. Tsdu,
  1052. MPX_HEADER_SIZE,
  1053. ReceiveDatagramFlags
  1054. );
  1055. status = STATUS_PENDING;
  1056. } else {
  1057. TdiCopyLookaheadData(
  1058. workContext->RequestBuffer->Buffer,
  1059. Tsdu,
  1060. BytesIndicated,
  1061. ReceiveDatagramFlags
  1062. );
  1063. // NB: status is set to STATUS_SUCCESS above!
  1064. }
  1065. #if SRVDBG_PERF
  1066. if ( Trap512s ) {
  1067. if ( header->Command == SMB_COM_READ ) {
  1068. PREQ_READ request = (PREQ_READ)(header + 1);
  1069. if ( (SmbGetUshort(&request->Count) == 512) &&
  1070. ((SmbGetUlong(&request->Offset) & 511) == 0) ) {
  1071. PRESP_READ response;
  1072. if (Break512s) DbgBreakPoint();
  1073. Trapped512s++;
  1074. response = (PRESP_READ)workContext->ResponseParameters;
  1075. response->WordCount = 5;
  1076. SmbPutUshort( &response->Count, 512 );
  1077. RtlZeroMemory( (PVOID)&response->Reserved[0], sizeof(response->Reserved) );
  1078. SmbPutUshort(
  1079. &response->ByteCount,
  1080. (USHORT)(512 + FIELD_OFFSET(RESP_READ,Buffer[0]) -
  1081. FIELD_OFFSET(RESP_READ,BufferFormat))
  1082. );
  1083. response->BufferFormat = SMB_FORMAT_DATA;
  1084. SmbPutUshort( &response->DataLength, 512 );
  1085. workContext->ResponseParameters = NEXT_LOCATION(
  1086. response,
  1087. RESP_READ,
  1088. 512
  1089. );
  1090. SrvFsdSendResponse( workContext );
  1091. return STATUS_SUCCESS;
  1092. }
  1093. }
  1094. }
  1095. #endif // SRVDBG_PERF
  1096. queue_to_fsp:
  1097. //
  1098. // Pretend the transport completed an IRP by doing what the
  1099. // restart routine, which is known to be
  1100. // SrvQueueWorkToFspAtDpcLevel, would do.
  1101. //
  1102. irp->IoStatus.Status = STATUS_SUCCESS;
  1103. irp->IoStatus.Information = BytesIndicated;
  1104. irp->Cancel = FALSE;
  1105. //
  1106. // *** THE FOLLOWING IS COPIED FROM SrvQueueWorkToFspAtDpcLevel.
  1107. //
  1108. // Increment the processing count.
  1109. //
  1110. workContext->ProcessingCount++;
  1111. //
  1112. // Insert the work item into the work queue
  1113. //
  1114. if( workContext->QueueToHead ) {
  1115. SrvInsertWorkQueueHead(
  1116. workQueue,
  1117. (PQUEUEABLE_BLOCK_HEADER)workContext
  1118. );
  1119. } else {
  1120. SrvInsertWorkQueueTail(
  1121. workQueue,
  1122. (PQUEUEABLE_BLOCK_HEADER)workContext
  1123. );
  1124. }
  1125. KeLowerIrql( oldIrql );
  1126. return status;
  1127. }
  1128. build_irp:
  1129. //
  1130. // We can't copy the indicated data. Set up the receive IRP.
  1131. //
  1132. ASSERT( workQueue != NULL );
  1133. irp->Tail.Overlay.OriginalFileObject = NULL;
  1134. irp->Tail.Overlay.Thread = workQueue->IrpThread;
  1135. DEBUG irp->RequestorMode = KernelMode;
  1136. //
  1137. // Set up the completion routine.
  1138. //
  1139. IoSetCompletionRoutine(
  1140. irp,
  1141. SrvFsdIoCompletionRoutine,
  1142. workContext,
  1143. TRUE,
  1144. TRUE,
  1145. TRUE
  1146. );
  1147. //
  1148. // Make the next stack location current. Normally IoCallDriver
  1149. // would do this, but since we're bypassing that, we do it directly.
  1150. // Load the target device object address into the stack location.
  1151. // This especially important because the server likes to reuse IRPs.
  1152. //
  1153. // Get a pointer to the next stack location. This one is used to
  1154. // hold the parameters for the device I/O control request.
  1155. //
  1156. IoSetNextIrpStackLocation( irp );
  1157. irpSp = IoGetCurrentIrpStackLocation( irp );
  1158. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1159. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE_DATAGRAM;
  1160. //
  1161. // Copy the caller's parameters to the service-specific portion of the
  1162. // IRP for those parameters that are the same for all three methods.
  1163. //
  1164. requestBuffer = workContext->RequestBuffer;
  1165. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  1166. parameters->ReceiveLength = requestBuffer->BufferLength;
  1167. parameters->ReceiveFlags = 0;
  1168. irp->MdlAddress = requestBuffer->Mdl;
  1169. irp->AssociatedIrp.SystemBuffer = NULL;
  1170. irpSp->Flags = 0;
  1171. irpSp->DeviceObject = endpoint->DeviceObject;
  1172. irpSp->FileObject = endpoint->FileObject;
  1173. ASSERT( irp->StackCount >= irpSp->DeviceObject->StackSize );
  1174. //
  1175. // Return STATUS_MORE_PROCESSING_REQUIRED so that the transport
  1176. // provider will use our IRP to service the receive.
  1177. //
  1178. *IoRequestPacket = irp;
  1179. *BytesTaken = 0;
  1180. KeLowerIrql( oldIrql );
  1181. return STATUS_MORE_PROCESSING_REQUIRED;
  1182. bad_fid:
  1183. //
  1184. // An invalid FID was specified on a Write Mpx request, or there was
  1185. // a saved write behind error in the RFCB. If this is an
  1186. // unsequenced request, we drop it on the floor. If it's a
  1187. // sequenced request, we send an error response.
  1188. //
  1189. if ( sequenceNumber == 0 ) {
  1190. stale_mid:
  1191. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1192. goto return_connection;
  1193. }
  1194. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1195. ASSERT( workContext->Connection != NULL );
  1196. SrvFreeIpxConnectionInIndication( workContext );
  1197. resend = FALSE;
  1198. goto respond;
  1199. duplicate_request:
  1200. //
  1201. // This is a duplicate request. If it's still being processed,
  1202. // indicate that to the client.
  1203. //
  1204. if ( connection->LastResponseLength == (USHORT)-1 ) {
  1205. IF_DEBUG(IPX) KdPrint(( "SRVIPX: request in progress\n" ));
  1206. if( connection->IpxDuplicateCount++ < connection->IpxDropDuplicateCount ) {
  1207. //
  1208. // We drop every few duplicate request from the client
  1209. //
  1210. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1211. KeLowerIrql( oldIrql );
  1212. return STATUS_SUCCESS;
  1213. }
  1214. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1215. connection->IpxDuplicateCount = 0;
  1216. error = SMB_ERR_WORKING;
  1217. resend = FALSE;
  1218. } else {
  1219. //
  1220. // The request has already been completed. Resend the response.
  1221. //
  1222. IF_DEBUG(IPX) KdPrint(( "SRVIPX: resending response\n" ));
  1223. resend = TRUE;
  1224. }
  1225. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  1226. if( workContext == NULL ) {
  1227. if( resend == TRUE ) {
  1228. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1229. }
  1230. KeLowerIrql( oldIrql );
  1231. InterlockedIncrement( &connection->CurrentWorkQueue->NeedWorkItem );
  1232. return STATUS_SUCCESS;
  1233. }
  1234. respond:
  1235. ASSERT( workContext != NULL );
  1236. //
  1237. // Copy the received SMB header into the response buffer.
  1238. //
  1239. RtlCopyMemory(
  1240. workContext->ResponseBuffer->Buffer,
  1241. header,
  1242. sizeof(NT_SMB_HEADER)
  1243. );
  1244. header = (PNT_SMB_HEADER)workContext->ResponseBuffer->Buffer;
  1245. params = (PSMB_PARAMS)(header + 1);
  1246. header->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  1247. //
  1248. // Format the parameters portion of the SMB, and set the status.
  1249. //
  1250. if ( !resend ) {
  1251. SmbPutUshort( &header->Status.DosError.Error, error );
  1252. header->Status.DosError.ErrorClass = SMB_ERR_CLASS_SERVER;
  1253. header->Status.DosError.Reserved = 0;
  1254. params->WordCount = 0;
  1255. SmbPutUshort( &params->ByteCount, 0 );
  1256. length = sizeof(NT_SMB_HEADER) + sizeof(SMB_PARAMS);
  1257. } else {
  1258. //
  1259. // Copy the saved response data into the response.
  1260. //
  1261. SmbPutUlong( &header->Status.NtStatus, connection->LastResponseStatus );
  1262. SmbPutUshort( &header->Tid, connection->LastTid);
  1263. SmbPutUshort( &header->Uid, connection->LastUid);
  1264. RtlCopyMemory(
  1265. (PVOID)params,
  1266. connection->LastResponse,
  1267. connection->LastResponseLength
  1268. );
  1269. length = sizeof(NT_SMB_HEADER) + connection->LastResponseLength;
  1270. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1271. }
  1272. workContext->ResponseBuffer->DataLength = length;
  1273. workContext->ResponseBuffer->Mdl->ByteCount = length;
  1274. //
  1275. // Format the destination address.
  1276. //
  1277. workContext->ClientAddress->IpxAddress = *(PTA_IPX_ADDRESS)SourceAddress;
  1278. workContext->ClientAddress->DatagramOptions =
  1279. *(PIPX_DATAGRAM_OPTIONS)Options;
  1280. //
  1281. // Send the packet.
  1282. //
  1283. workContext->Endpoint = endpoint;
  1284. DEBUG workContext->FsdRestartRoutine = NULL;
  1285. StartSendNoConnection( workContext, FALSE, TRUE );
  1286. KeLowerIrql( oldIrql );
  1287. return STATUS_SUCCESS;
  1288. return_connection:
  1289. SrvFreeIpxConnectionInIndication( workContext );
  1290. KeLowerIrql( oldIrql );
  1291. workContext->BlockHeader.ReferenceCount = 0;
  1292. RETURN_FREE_WORKITEM( workContext );
  1293. return STATUS_SUCCESS;
  1294. } // SrvIpxServerDatagramHandlerCommon
  1295. NTSTATUS
  1296. SrvIpxServerDatagramHandler (
  1297. IN PVOID TdiEventContext,
  1298. IN int SourceAddressLength,
  1299. IN PVOID SourceAddress,
  1300. IN int OptionsLength,
  1301. IN PVOID Options,
  1302. IN ULONG ReceiveDatagramFlags,
  1303. IN ULONG BytesIndicated,
  1304. IN ULONG BytesAvailable,
  1305. OUT ULONG *BytesTaken,
  1306. IN PVOID Tsdu,
  1307. OUT PIRP *IoRequestPacket
  1308. )
  1309. /*++
  1310. Routine Description:
  1311. This is the receive datagram event handler for the IPX server socket.
  1312. It attempts to dequeue a preformatted work item from a list
  1313. anchored in the device object. If this is successful, it returns
  1314. the IRP associated with the work item to the transport provider to
  1315. be used to receive the data. Otherwise, the message is dropped.
  1316. Arguments:
  1317. TdiEventContext - Pointer to receiving endpoint
  1318. SourceAddressLength - Length of SourceAddress
  1319. SourceAddress - Address of sender
  1320. OptionsLength - Length of options
  1321. Options - Options for the receive
  1322. ReceiveDatagramFlags - Set of flags indicating the status of the
  1323. received message
  1324. BytesIndicated - Number of bytes in this indication (lookahead)
  1325. BytesAvailable - Number of bytes in the complete TSDU
  1326. BytesTaken - Returns the number of bytes taken by the handler
  1327. Tsdu - Pointer to buffer describing the Transport Service Data Unit
  1328. IoRequestPacket - Returns a pointer to I/O request packet, if the
  1329. returned status is STATUS_MORE_PROCESSING_REQUIRED. This IRP is
  1330. made the 'current' Receive for the endpoint.
  1331. Return Value:
  1332. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  1333. processed the request. If STATUS_MORE_PROCESSING_REQUIRED,
  1334. the Irp parameter points to a formatted Receive request to
  1335. be used to receive the data. If STATUS_DATA_NOT_ACCEPTED,
  1336. the message is lost.
  1337. --*/
  1338. {
  1339. NTSTATUS status;
  1340. status = SrvIpxServerDatagramHandlerCommon(
  1341. TdiEventContext,
  1342. SourceAddressLength,
  1343. SourceAddress,
  1344. OptionsLength,
  1345. Options,
  1346. ReceiveDatagramFlags,
  1347. BytesIndicated,
  1348. BytesAvailable,
  1349. BytesTaken,
  1350. Tsdu,
  1351. IoRequestPacket,
  1352. NULL
  1353. );
  1354. ASSERT( status != STATUS_PENDING );
  1355. return status;
  1356. } // SrvIpxServerDatagramHandler
  1357. NTSTATUS
  1358. SrvIpxServerChainedDatagramHandler (
  1359. IN PVOID TdiEventContext,
  1360. IN int SourceAddressLength,
  1361. IN PVOID SourceAddress,
  1362. IN int OptionsLength,
  1363. IN PVOID Options,
  1364. IN ULONG ReceiveDatagramFlags,
  1365. IN ULONG ReceiveDatagramLength,
  1366. IN ULONG StartingOffset,
  1367. IN PMDL Tsdu,
  1368. IN PVOID TransportContext
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. This is the receive datagram event handler for the IPX server socket.
  1373. It attempts to dequeue a preformatted work item from a list
  1374. anchored in the device object. If this is successful, it returns
  1375. the IRP associated with the work item to the transport provider to
  1376. be used to receive the data. Otherwise, the message is dropped.
  1377. Arguments:
  1378. TdiEventContext - Pointer to receiving endpoint
  1379. SourceAddressLength - Length of SourceAddress
  1380. SourceAddress - Address of sender
  1381. OptionsLength - Length of options
  1382. Options - Options for the receive
  1383. ReceiveDatagramFlags - Set of flags indicating the status of the
  1384. received message
  1385. ReceiveDatagramLength - The length in byutes of the client data in the Tsdu
  1386. StartingOffset - Offset, in bytes, from beginning of Tsdu to client's data
  1387. Tsdu - Pointer to an MDL chain describing the received data
  1388. TranportContext - Context to be passed to TdiReturnChainedReceives if
  1389. buffer is taken
  1390. Return Value:
  1391. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  1392. processed the request. If STATUS_PENDING, the receive buffer was
  1393. taken and it will be returned via TdiReturnChainedReceives. If
  1394. If STATUS_DATA_NOT_ACCEPTED, the message is lost.
  1395. --*/
  1396. {
  1397. PVOID receiveBuffer;
  1398. ULONG bytesTaken;
  1399. NTSTATUS status;
  1400. PIRP ioRequestPacket = NULL;
  1401. ASSERT( StartingOffset < 512 );
  1402. receiveBuffer = (PCHAR)MmGetSystemAddressForMdl( Tsdu ) + StartingOffset;
  1403. status = SrvIpxServerDatagramHandlerCommon(
  1404. TdiEventContext,
  1405. SourceAddressLength,
  1406. SourceAddress,
  1407. OptionsLength,
  1408. Options,
  1409. ReceiveDatagramFlags,
  1410. ReceiveDatagramLength,
  1411. ReceiveDatagramLength,
  1412. &bytesTaken,
  1413. receiveBuffer,
  1414. &ioRequestPacket,
  1415. TransportContext
  1416. );
  1417. ASSERT( ioRequestPacket == NULL );
  1418. DEBUG if ( status == STATUS_PENDING ) {
  1419. ASSERT( bytesTaken == ReceiveDatagramLength );
  1420. }
  1421. return status;
  1422. } // SrvIpxServerChainedDatagramHandler
  1423. VOID
  1424. SrvIpxStartSend (
  1425. IN OUT PWORK_CONTEXT WorkContext,
  1426. IN PIO_COMPLETION_ROUTINE SendCompletionRoutine
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This function sends an SMB/IPX name claim request or response. It
  1431. is started as an asynchronous I/O request. When the Send completes,
  1432. the restart routine preloaded into the work context is called.
  1433. Arguments:
  1434. WorkContext - Supplies a pointer to a Work Context block
  1435. Return Value:
  1436. None.
  1437. --*/
  1438. {
  1439. PENDPOINT endpoint;
  1440. PCONNECTION connection;
  1441. PTDI_REQUEST_KERNEL_SENDDG parameters;
  1442. PIO_STACK_LOCATION irpSp;
  1443. PIRP irp;
  1444. PMDL mdl;
  1445. ULONG sendLength;
  1446. USHORT responseLength;
  1447. PDEVICE_OBJECT deviceObject;
  1448. PFILE_OBJECT fileObject;
  1449. PTDI_CONNECTION_INFORMATION destination;
  1450. PNT_SMB_HEADER header;
  1451. // IF_DEBUG(IPX2) SrvPrint0( "SrvIpxStartSend entered\n" );
  1452. //
  1453. // Set ProcessingCount to zero so this send cannot be cancelled.
  1454. // This is used together with setting the cancel flag to false below.
  1455. //
  1456. // WARNING: This still presents us with a tiny window where this
  1457. // send could be cancelled.
  1458. //
  1459. WorkContext->ProcessingCount = 0;
  1460. //
  1461. // Count up the length of the data described by chained MDLs.
  1462. //
  1463. sendLength = WorkContext->ResponseBuffer->DataLength;
  1464. //
  1465. // Get the MDL pointer.
  1466. //
  1467. mdl = WorkContext->ResponseBuffer->Mdl;
  1468. //
  1469. // Build the I/O request packet.
  1470. //
  1471. // *** Note that the connection block is not referenced to account
  1472. // for this I/O request. The WorkContext block already has a
  1473. // referenced pointer to the connection, and this pointer is not
  1474. // dereferenced until after the I/O completes.
  1475. //
  1476. irp = WorkContext->Irp;
  1477. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1478. DEBUG irp->RequestorMode = KernelMode;
  1479. //
  1480. // Get a pointer to the next stack location. This one is used to
  1481. // hold the parameters for the device I/O control request.
  1482. //
  1483. irpSp = IoGetNextIrpStackLocation( irp );
  1484. //
  1485. // Set up the completion routine.
  1486. //
  1487. IoSetCompletionRoutine(
  1488. irp,
  1489. SendCompletionRoutine,
  1490. (PVOID)WorkContext,
  1491. TRUE,
  1492. TRUE,
  1493. TRUE
  1494. );
  1495. destination = &WorkContext->ClientAddress->Descriptor;
  1496. destination->UserDataLength = 0;
  1497. destination->OptionsLength = sizeof(IPX_DATAGRAM_OPTIONS);
  1498. destination->Options = &WorkContext->ClientAddress->DatagramOptions;
  1499. destination->RemoteAddressLength = sizeof(TA_IPX_ADDRESS);
  1500. destination->RemoteAddress = &WorkContext->ClientAddress->IpxAddress;
  1501. parameters = (PTDI_REQUEST_KERNEL_SENDDG)&irpSp->Parameters;
  1502. parameters->SendLength = sendLength;
  1503. parameters->SendDatagramInformation = destination;
  1504. endpoint = WorkContext->Endpoint;
  1505. ASSERT( endpoint->IsConnectionless );
  1506. deviceObject = endpoint->DeviceObject;
  1507. fileObject = endpoint->FileObject;
  1508. ASSERT( irp->StackCount >= deviceObject->StackSize );
  1509. irp->MdlAddress = mdl;
  1510. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1511. irpSp->FileObject = fileObject;
  1512. //
  1513. // If this is a sequenced message, save the response data.
  1514. //
  1515. header = (PNT_SMB_HEADER)WorkContext->ResponseHeader;
  1516. ASSERT( header != NULL );
  1517. connection = WorkContext->Connection;
  1518. ASSERT( connection != NULL );
  1519. if ( SmbGetAlignedUshort(&header->SequenceNumber) != 0 ) {
  1520. IF_DEBUG(IPX) {
  1521. KdPrint(("SRVIPX: Responding to sequenced request %x mid=%x, connection %p\n",
  1522. SmbGetAlignedUshort(&header->SequenceNumber),
  1523. SmbGetAlignedUshort(&header->Mid), connection ));
  1524. }
  1525. ASSERT( sendLength - sizeof(SMB_HEADER) < 0x10000 );
  1526. responseLength = (USHORT)(sendLength - sizeof(SMB_HEADER));
  1527. IF_DEBUG(IPX) {
  1528. KdPrint(("SRVIPX: parameters length %x, max=%x\n",
  1529. responseLength, MAX_SAVED_RESPONSE_LENGTH ));
  1530. }
  1531. if ( responseLength > MAX_SAVED_RESPONSE_LENGTH ) {
  1532. //
  1533. // The response is too large to save. The client shouldn't
  1534. // be doing this, except on transactions, for which we save
  1535. // a copy of the full response.
  1536. //
  1537. if ( (header->Command == SMB_COM_TRANSACTION) ||
  1538. (header->Command == SMB_COM_TRANSACTION_SECONDARY) ||
  1539. (header->Command == SMB_COM_TRANSACTION2) ||
  1540. (header->Command == SMB_COM_TRANSACTION2_SECONDARY) ) {
  1541. //
  1542. // We need a buffer to hold the response. If a buffer
  1543. // has already been allocated, and is large enough, use
  1544. // it. Otherwise, allocate one.
  1545. //
  1546. IF_DEBUG(IPX) {
  1547. KdPrint(("SRVIPX: transaction; saving long response\n" ));
  1548. }
  1549. if ( (connection->LastResponse == connection->BuiltinSavedResponse) ||
  1550. (connection->LastResponseBufferLength < responseLength) ) {
  1551. PVOID resp = ALLOCATE_NONPAGED_POOL( responseLength, BlockTypeDataBuffer );
  1552. if( resp != NULL ) {
  1553. if ( connection->LastResponse != connection->BuiltinSavedResponse ) {
  1554. IF_DEBUG(IPX) {
  1555. KdPrint(("SRVIPX: deallocating old response buffer %p\n",
  1556. connection->LastResponse ));
  1557. }
  1558. DEALLOCATE_NONPAGED_POOL( connection->LastResponse );
  1559. }
  1560. connection->LastResponse = resp;
  1561. IF_DEBUG(IPX) {
  1562. KdPrint(("SRVIPX: new response buffer %p\n",
  1563. connection->LastResponse ));
  1564. }
  1565. connection->LastResponseBufferLength = responseLength;
  1566. }
  1567. }
  1568. } else {
  1569. IF_DEBUG(IPX) {
  1570. KdPrint(("SRVIPX: not a transaction; illegal long response\n" ));
  1571. }
  1572. SmbPutUshort( &header->Status.DosError.Error, SMB_ERR_ERROR );
  1573. header->Status.DosError.ErrorClass = SMB_ERR_CLASS_SERVER;
  1574. header->Status.DosError.Reserved = 0;
  1575. *(PLONG)(header + 1) = 0; // set WCT and BCC to 0
  1576. sendLength = sizeof(SMB_HEADER) + sizeof(SMB_PARAMS);
  1577. responseLength = 3;
  1578. mdl->ByteCount = sendLength;
  1579. parameters->SendLength = sendLength;
  1580. goto small_response;
  1581. }
  1582. } else {
  1583. small_response:
  1584. //
  1585. // The response fits in the built-in buffer.
  1586. //
  1587. IF_DEBUG(IPX) {
  1588. KdPrint(("SRVIPX: response fits in builtin response buffer\n" ));
  1589. }
  1590. if ( connection->LastResponse != connection->BuiltinSavedResponse ) {
  1591. IF_DEBUG(IPX) {
  1592. KdPrint(("SRVIPX: deallocating old response buffer %p\n",
  1593. connection->LastResponse ));
  1594. }
  1595. DEALLOCATE_NONPAGED_POOL( connection->LastResponse );
  1596. connection->LastResponse = connection->BuiltinSavedResponse;
  1597. connection->LastResponseBufferLength = sizeof( connection->BuiltinSavedResponse );
  1598. }
  1599. }
  1600. //
  1601. // Save the response data in the connection.
  1602. //
  1603. connection->LastResponseStatus = SmbGetUlong( &header->Status.NtStatus );
  1604. connection->LastUid = SmbGetUshort( &header->Uid );
  1605. connection->LastTid = SmbGetUshort( &header->Tid );
  1606. connection->LastResponseLength = MIN( responseLength, connection->LastResponseBufferLength );
  1607. RtlCopyMemory( connection->LastResponse, (header + 1), connection->LastResponseLength );
  1608. } else {
  1609. IF_DEBUG(IPX) {
  1610. KdPrint(("SRVIPX: Responding to unsequenced request mid=%x\n",
  1611. SmbGetAlignedUshort(&header->Mid) ));
  1612. }
  1613. }
  1614. //
  1615. // If statistics are to be gathered for this work item, do so now.
  1616. //
  1617. UPDATE_STATISTICS(
  1618. WorkContext,
  1619. sendLength,
  1620. WorkContext->ResponseHeader->Command
  1621. );
  1622. //
  1623. // Pass the request to the transport provider.
  1624. //
  1625. //
  1626. // Increment the pending operation count
  1627. //
  1628. InterlockedIncrement( &WorkContext->Connection->OperationsPendingOnTransport );
  1629. //
  1630. // Set the cancel flag to FALSE in case this was cancelled by
  1631. // the SrvSmbNtCancel routine.
  1632. //
  1633. if ( endpoint->FastTdiSendDatagram ) {
  1634. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.DirectSendsAttempted );
  1635. DEBUG irpSp->DeviceObject = deviceObject;
  1636. irpSp->MinorFunction = TDI_DIRECT_SEND_DATAGRAM;
  1637. IoSetNextIrpStackLocation( irp );
  1638. irp->Cancel = FALSE;
  1639. endpoint->FastTdiSendDatagram( deviceObject, irp );
  1640. } else {
  1641. irp->AssociatedIrp.SystemBuffer = NULL;
  1642. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1643. irp->Cancel = FALSE;
  1644. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1645. irpSp->MinorFunction = TDI_SEND_DATAGRAM;
  1646. (VOID)IoCallDriver( deviceObject, irp );
  1647. }
  1648. return;
  1649. } // SrvIpxStartSend
  1650. VOID
  1651. StartSendNoConnection (
  1652. IN OUT PWORK_CONTEXT WorkContext,
  1653. IN BOOLEAN UseNameSocket,
  1654. IN BOOLEAN LocalTargetValid
  1655. )
  1656. /*++
  1657. Routine Description:
  1658. This function sends an SMB/IPX name claim request or response. It
  1659. is started as an asynchronous I/O request. When the Send completes,
  1660. the restart routine preloaded into the work context is called.
  1661. Arguments:
  1662. WorkContext - Supplies a pointer to a Work Context block
  1663. UseNameSocket - Indicates whether the name socket or the server
  1664. socket is to be used.
  1665. Return Value:
  1666. None.
  1667. --*/
  1668. {
  1669. PENDPOINT endpoint;
  1670. PTDI_REQUEST_KERNEL_SENDDG parameters;
  1671. PIO_STACK_LOCATION irpSp;
  1672. PIRP irp;
  1673. ULONG sendLength;
  1674. PDEVICE_OBJECT deviceObject;
  1675. PFILE_OBJECT fileObject;
  1676. PTDI_CONNECTION_INFORMATION destination;
  1677. //
  1678. // Set ProcessingCount to zero so this send cannot be cancelled.
  1679. // This is used together with setting the cancel flag to false below.
  1680. //
  1681. // WARNING: This still presents us with a tiny window where this
  1682. // send could be cancelled.
  1683. //
  1684. WorkContext->ProcessingCount = 0;
  1685. //
  1686. // Count up the length of the data described by chained MDLs.
  1687. //
  1688. sendLength = WorkContext->ResponseBuffer->DataLength;
  1689. //
  1690. // Build the I/O request packet.
  1691. //
  1692. // *** Note that the connection block is not referenced to account
  1693. // for this I/O request. The WorkContext block already has a
  1694. // referenced pointer to the connection, and this pointer is not
  1695. // dereferenced until after the I/O completes.
  1696. //
  1697. irp = WorkContext->Irp;
  1698. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1699. DEBUG irp->RequestorMode = KernelMode;
  1700. //
  1701. // Get a pointer to the next stack location. This one is used to
  1702. // hold the parameters for the device I/O control request.
  1703. //
  1704. irpSp = IoGetNextIrpStackLocation( irp );
  1705. //
  1706. // Set up the completion routine.
  1707. //
  1708. IoSetCompletionRoutine(
  1709. irp,
  1710. RequeueIpxWorkItemAtSendCompletion,
  1711. (PVOID)WorkContext,
  1712. TRUE,
  1713. TRUE,
  1714. TRUE
  1715. );
  1716. destination = &WorkContext->ClientAddress->Descriptor;
  1717. destination->UserDataLength = 0;
  1718. destination->OptionsLength =
  1719. LocalTargetValid ? sizeof(IPX_DATAGRAM_OPTIONS) : sizeof(UCHAR);
  1720. ASSERT( FIELD_OFFSET( IPX_DATAGRAM_OPTIONS, PacketType ) == 0 );
  1721. destination->Options = &WorkContext->ClientAddress->DatagramOptions;
  1722. destination->RemoteAddressLength = sizeof(TA_IPX_ADDRESS);
  1723. destination->RemoteAddress = &WorkContext->ClientAddress->IpxAddress;
  1724. parameters = (PTDI_REQUEST_KERNEL_SENDDG)&irpSp->Parameters;
  1725. parameters->SendLength = sendLength;
  1726. parameters->SendDatagramInformation = destination;
  1727. irp->MdlAddress = WorkContext->ResponseBuffer->Mdl;
  1728. endpoint = WorkContext->Endpoint;
  1729. ASSERT( endpoint->IsConnectionless );
  1730. if ( !UseNameSocket ) {
  1731. deviceObject = endpoint->DeviceObject;
  1732. fileObject = endpoint->FileObject;
  1733. } else {
  1734. deviceObject = endpoint->NameSocketDeviceObject;
  1735. fileObject = endpoint->NameSocketFileObject;
  1736. }
  1737. ASSERT( irp->StackCount >= deviceObject->StackSize );
  1738. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1739. irpSp->FileObject = fileObject;
  1740. //
  1741. // Pass the request to the transport provider.
  1742. //
  1743. //
  1744. // Set the cancel flag to FALSE in case this was cancelled by
  1745. // the SrvSmbNtCancel routine.
  1746. //
  1747. irp->Cancel = FALSE;
  1748. if ( endpoint->FastTdiSendDatagram ) {
  1749. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.DirectSendsAttempted );
  1750. DEBUG irpSp->DeviceObject = deviceObject;
  1751. irpSp->MinorFunction = TDI_DIRECT_SEND_DATAGRAM;
  1752. IoSetNextIrpStackLocation( irp );
  1753. endpoint->FastTdiSendDatagram( deviceObject, irp );
  1754. } else {
  1755. irp->AssociatedIrp.SystemBuffer = NULL;
  1756. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1757. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1758. irpSp->MinorFunction = TDI_SEND_DATAGRAM;
  1759. (VOID)IoCallDriver( deviceObject, irp );
  1760. }
  1761. return;
  1762. } // StartSendNoConnection
  1763. VOID SRVFASTCALL
  1764. IpxRestartReceive (
  1765. IN OUT PWORK_CONTEXT WorkContext
  1766. )
  1767. /*++
  1768. Routine Description:
  1769. This is the restart routine for IPX Receive completion. It does
  1770. some IPX-specific setup work, then calls SrvRestartReceive.
  1771. Arguments:
  1772. WorkContext - Supplies a pointer to the work context block
  1773. describing server-specific context for the request.
  1774. Return Value:
  1775. None.
  1776. --*/
  1777. {
  1778. PSMB_HEADER header = (PSMB_HEADER)WorkContext->RequestBuffer->Buffer;
  1779. PAGED_CODE( );
  1780. ASSERT( header->Command == SMB_COM_NEGOTIATE );
  1781. //
  1782. // Get rid of stale connections.
  1783. //
  1784. IF_DEBUG(IPX) KdPrint(( "SRVIPX: processing Negotiate\n" ));
  1785. PurgeIpxConnections( WorkContext->Endpoint );
  1786. //
  1787. // Load the SID from the connection into the request. Since this
  1788. // is a Negotiate request, we need to return a SID to the client.
  1789. // The easiest way to ensure that happens is to save the SID here.
  1790. //
  1791. SmbPutAlignedUshort( &header->Sid, WorkContext->Connection->Sid );
  1792. //
  1793. // Call the normal SMB processing routine.
  1794. //
  1795. SrvRestartReceive( WorkContext );
  1796. return;
  1797. } // IpxRestartReceive
  1798. NTSTATUS
  1799. RequeueIpxWorkItemAtSendCompletion (
  1800. IN PDEVICE_OBJECT DeviceObject,
  1801. IN PIRP Irp,
  1802. IN OUT PWORK_CONTEXT WorkContext
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This routine requeues an IPX work item to the free queue.
  1807. Arguments:
  1808. DeviceObject - Pointer to target device object for the request.
  1809. Irp - Pointer to I/O request packet
  1810. WorkContext - Caller-specified context parameter associated with IRP.
  1811. This is actually a pointer to a Work Context block.
  1812. Return Value:
  1813. STATUS_MORE_PROCESSING_REQUIRED.
  1814. --*/
  1815. {
  1816. //
  1817. // Check the status of the send completion.
  1818. //
  1819. CHECK_SEND_COMPLETION_STATUS_CONNECTIONLESS( Irp->IoStatus.Status );
  1820. //
  1821. // Reset the IRP cancelled bit.
  1822. //
  1823. Irp->Cancel = FALSE;
  1824. ASSERT( WorkContext->BlockHeader.ReferenceCount == 1 );
  1825. WorkContext->BlockHeader.ReferenceCount = 0;
  1826. ASSERT( WorkContext->Share == NULL );
  1827. ASSERT( WorkContext->Session == NULL );
  1828. ASSERT( WorkContext->TreeConnect == NULL );
  1829. ASSERT( WorkContext->Rfcb == NULL );
  1830. //
  1831. // Set up the restart routine in the work context.
  1832. //
  1833. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1834. WorkContext->FspRestartRoutine = SrvRestartReceive;
  1835. //
  1836. // Make sure the length specified in the MDL is correct -- it may
  1837. // have changed while sending a response to the previous request.
  1838. // Call an I/O subsystem routine to build the I/O request packet.
  1839. //
  1840. WorkContext->RequestBuffer->Mdl->ByteCount =
  1841. WorkContext->RequestBuffer->BufferLength;
  1842. //
  1843. // Requeue the work item.
  1844. //
  1845. RETURN_FREE_WORKITEM( WorkContext );
  1846. return STATUS_MORE_PROCESSING_REQUIRED;
  1847. } // RequeueIpxWorkItemAtSendCompletion
  1848. PCONNECTION
  1849. GetIpxConnection (
  1850. IN PWORK_CONTEXT WorkContext,
  1851. IN PENDPOINT Endpoint,
  1852. IN PTDI_ADDRESS_IPX ClientAddress,
  1853. IN PUCHAR ClientName
  1854. )
  1855. {
  1856. PLIST_ENTRY listEntry;
  1857. PCONNECTION connection;
  1858. PCHAR clientMachineName;
  1859. ULONG length;
  1860. KIRQL oldIrql;
  1861. PWORK_QUEUE queue = PROCESSOR_TO_QUEUE();
  1862. //
  1863. // Take a connection off the endpoint's free connection list.
  1864. //
  1865. // *** Note that all of the modifications done to the connection
  1866. // block are done with the spin lock held. This ensures that
  1867. // closing of the endpoint's connections will work properly if
  1868. // it happens simultaneously.
  1869. //
  1870. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  1871. listEntry = RemoveHeadList( &Endpoint->FreeConnectionList );
  1872. if ( listEntry == &Endpoint->FreeConnectionList ) {
  1873. //
  1874. // Unable to get a free connection.
  1875. //
  1876. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  1877. IF_DEBUG(IPX) KdPrint(( "SRVIPX: no free connections\n" ));
  1878. SrvOutOfFreeConnectionCount++;
  1879. return NULL;
  1880. }
  1881. //
  1882. // We have a connection and a table entry.
  1883. //
  1884. Endpoint->FreeConnectionCount--;
  1885. //
  1886. // Wake up the resource thread to create a new free connection
  1887. // for the endpoint.
  1888. //
  1889. if ( (Endpoint->FreeConnectionCount < SrvFreeConnectionMinimum) &&
  1890. (GET_BLOCK_STATE(Endpoint) == BlockStateActive) ) {
  1891. SrvResourceAllocConnection = TRUE;
  1892. SrvFsdQueueExWorkItem(
  1893. &SrvResourceAllocThreadWorkItem,
  1894. &SrvResourceAllocThreadRunning,
  1895. CriticalWorkQueue
  1896. );
  1897. }
  1898. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  1899. //
  1900. // Reference the connection to account for its being "open" and
  1901. // for the work item's pointer.
  1902. //
  1903. connection = CONTAINING_RECORD(
  1904. listEntry,
  1905. CONNECTION,
  1906. EndpointFreeListEntry
  1907. );
  1908. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  1909. SrvReferenceConnectionLocked( connection );
  1910. SrvReferenceConnectionLocked( connection );
  1911. //
  1912. // Mark the connection active.
  1913. //
  1914. SET_BLOCK_STATE( connection, BlockStateActive );
  1915. //
  1916. // Initialize IPX protocol fields.
  1917. //
  1918. connection->DirectHostIpx = TRUE;
  1919. connection->IpxAddress = *ClientAddress;
  1920. connection->SequenceNumber = 0;
  1921. connection->LastResponseLength = (USHORT)-1;
  1922. //
  1923. // Set the processor affinity
  1924. //
  1925. connection->PreferredWorkQueue = queue;
  1926. connection->CurrentWorkQueue = queue;
  1927. InterlockedIncrement( &queue->CurrentClients );
  1928. //
  1929. // Set the duplicate drop count. Start off conservative until
  1930. // we learn what kind of client we're dealing with
  1931. //
  1932. connection->IpxDropDuplicateCount = MIN_IPXDROPDUP;
  1933. connection->IpxDuplicateCount = 0;
  1934. #if MULTIPROCESSOR
  1935. //
  1936. // Get this client onto the best possible processor
  1937. //
  1938. SrvBalanceLoad( connection );
  1939. #endif
  1940. //
  1941. // Set time stamps. StartupTime is used by the server to determine
  1942. // whether the connection is old enough to be considered stale and
  1943. // should be closed when another negotiate comes in. This is used
  1944. // to fix a timing problem where identical negotiates may be
  1945. // queued up the the worker thread and a session setup comes in which
  1946. // gets partially processed in the indication routine.
  1947. //
  1948. SET_SERVER_TIME( connection->CurrentWorkQueue );
  1949. GET_SERVER_TIME( connection->CurrentWorkQueue, &connection->StartupTime );
  1950. connection->LastRequestTime = connection->StartupTime;
  1951. //
  1952. // Put the work item on the in-progress list.
  1953. //
  1954. SrvInsertTailList(
  1955. &connection->InProgressWorkItemList,
  1956. &WorkContext->InProgressListEntry
  1957. );
  1958. connection->InProgressWorkContextCount++;
  1959. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1960. WorkContext->Connection = connection;
  1961. //
  1962. // Copy the oem name at this time. We convert it to Unicode
  1963. // when we get the Session Setup SMB.
  1964. //
  1965. clientMachineName = connection->OemClientMachineName;
  1966. RtlCopyMemory( clientMachineName, ClientName, SMB_IPX_NAME_LENGTH );
  1967. clientMachineName[SMB_IPX_NAME_LENGTH] = '\0';
  1968. //
  1969. // Determine the number of characters that aren't blanks. This
  1970. // is used by the session APIs to simplify their processing.
  1971. //
  1972. for ( length = SMB_IPX_NAME_LENGTH;
  1973. length > 0 &&
  1974. (clientMachineName[length-1] == ' ' ||
  1975. clientMachineName[length-1] == '\0');
  1976. length-- ) ;
  1977. connection->OemClientMachineNameString.Length = (USHORT)length;
  1978. IF_DEBUG(IPX) {
  1979. SrvPrint2( "IpxRestartReceive accepting connection from %z on connection %p\n",
  1980. (PCSTRING)&connection->OemClientMachineNameString, connection );
  1981. }
  1982. return connection;
  1983. } // GetIpxConnection
  1984. VOID
  1985. PurgeIpxConnections (
  1986. IN PENDPOINT Endpoint
  1987. )
  1988. {
  1989. USHORT i,j;
  1990. KIRQL oldIrql;
  1991. PTABLE_HEADER tableHeader;
  1992. PCONNECTION connection;
  1993. IF_DEBUG(IPX2) KdPrint(( "SRVIPX: PurgeIpxConnections entered\n" ));
  1994. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  1995. for ( j = 1; j < ENDPOINT_LOCK_COUNT; j++ ) {
  1996. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  1997. }
  1998. tableHeader = &Endpoint->ConnectionTable;
  1999. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  2000. connection = (PCONNECTION)tableHeader->Table[i].Owner;
  2001. if ( (connection == NULL) ||
  2002. (connection->IpxAddress.Socket != 0) ||
  2003. (GET_BLOCK_STATE(connection) != BlockStateActive) ) {
  2004. IF_DEBUG(IPX2) {
  2005. if ( connection == NULL ) {
  2006. KdPrint(( " no connection at table index %x\n", i ));
  2007. } else if ( connection->IpxAddress.Socket != 0 ) {
  2008. KdPrint(( " connection %p has socket %x\n", connection, connection->IpxAddress.Socket ));
  2009. } else {
  2010. KdPrint(( " connection %p has state %x\n", connection, GET_BLOCK_STATE(connection) ));
  2011. }
  2012. }
  2013. continue;
  2014. }
  2015. SrvReferenceConnectionLocked(connection);
  2016. for ( j = ENDPOINT_LOCK_COUNT-1; j > 0; j-- ) {
  2017. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2018. }
  2019. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2020. IF_DEBUG(IPX) KdPrint(( "SRVIPX: purging connection %p\n", connection ));
  2021. connection->DisconnectReason = DisconnectStaleIPXConnection;
  2022. SrvCloseConnection( connection, FALSE );
  2023. SrvDereferenceConnection( connection );
  2024. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  2025. for ( j = 1; j < ENDPOINT_LOCK_COUNT; j++ ) {
  2026. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2027. }
  2028. tableHeader = &Endpoint->ConnectionTable;
  2029. }
  2030. for ( j = ENDPOINT_LOCK_COUNT-1; j > 0; j-- ) {
  2031. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2032. }
  2033. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2034. IF_DEBUG(IPX2) KdPrint(( "SRVIPX: PurgeIpxConnections done\n" ));
  2035. return;
  2036. } // PurgeIpxConnections
  2037. VOID SRVFASTCALL
  2038. IpxRestartNegotiate(
  2039. IN OUT PWORK_CONTEXT WorkContext
  2040. )
  2041. /*++
  2042. Routine Description:
  2043. This routine handles the case where the transport did not
  2044. indicate us all of the data in the negotiate smb.
  2045. Arguments:
  2046. WorkContext - Supplies a pointer to the work context block
  2047. describing server-specific context for the request.
  2048. The workcontext block:
  2049. - has a pointer to the endpoint
  2050. - has a ref count of 1
  2051. Return Value:
  2052. None.
  2053. --*/
  2054. {
  2055. PENDPOINT endpoint;
  2056. USHORT sid;
  2057. PCONNECTION connection;
  2058. ULONG length;
  2059. PUCHAR clientName;
  2060. PTABLE_HEADER tableHeader;
  2061. USHORT i;
  2062. KIRQL oldIrql;
  2063. BOOLEAN resend;
  2064. USHORT error;
  2065. PLIST_ENTRY listEntry;
  2066. PTA_IPX_ADDRESS sourceAddress;
  2067. PNT_SMB_HEADER header;
  2068. PSMB_PARAMS params;
  2069. ASSERT( WorkContext->Endpoint != NULL );
  2070. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Negotiate received\n" ));
  2071. //
  2072. // If this endpoint is no longer around, ignore this request.
  2073. // This check covers the possibility that the endpoint has been
  2074. // removed between the time this request was queued to a worker
  2075. // thread and a worker thread actually picked up the request.
  2076. //
  2077. ACQUIRE_LOCK( &SrvEndpointLock );
  2078. listEntry = SrvEndpointList.ListHead.Flink;
  2079. while ( listEntry != &SrvEndpointList.ListHead ) {
  2080. endpoint = CONTAINING_RECORD(
  2081. listEntry,
  2082. ENDPOINT,
  2083. GlobalEndpointListEntry
  2084. );
  2085. if( endpoint == WorkContext->Endpoint &&
  2086. GET_BLOCK_STATE( endpoint ) == BlockStateActive ) {
  2087. //
  2088. // We found the endpoint, and it's still active! Reference
  2089. // it so the endpoint will not disappear out from under us.
  2090. //
  2091. endpoint->BlockHeader.ReferenceCount++;
  2092. break;
  2093. }
  2094. listEntry = listEntry->Flink;
  2095. }
  2096. if( listEntry == &SrvEndpointList.ListHead ) {
  2097. //
  2098. // We ran the whole list and did not find the endpoint. It
  2099. // must have gone away. Ignore this WorkItem.
  2100. //
  2101. RELEASE_LOCK( &SrvEndpointLock );
  2102. IF_DEBUG( IPX ) KdPrint(( "SRVIPX: Endpoint gone. ignoring\n" ));
  2103. goto return_workitem;
  2104. }
  2105. RELEASE_LOCK( &SrvEndpointLock );
  2106. //
  2107. // The endpoint is still valid, and we have referenced it. The local var
  2108. // 'endpoint' points to it.
  2109. //
  2110. sourceAddress = &WorkContext->ClientAddress->IpxAddress;
  2111. header = (PNT_SMB_HEADER) WorkContext->RequestHeader;
  2112. sid = SmbGetUshort( &header->Sid ); // NOT Aligned
  2113. ASSERT( sid == 0 );
  2114. clientName = (PUCHAR)WorkContext->RequestParameters;
  2115. clientName += 2 * (*clientName) + 1;
  2116. clientName += (*clientName) + 2;
  2117. //
  2118. // Make sure he's really trying to connect to us, and the SMB is well formed
  2119. //
  2120. if ( clientName+16+SMB_IPX_NAME_LENGTH-1 > END_OF_REQUEST_SMB( WorkContext ) ||
  2121. !RtlEqualMemory(
  2122. endpoint->TransportAddress.Buffer,
  2123. clientName + 16,
  2124. SMB_IPX_NAME_LENGTH ) ) {
  2125. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Negotiate sent to wrong name!\n" ));
  2126. error = SMB_ERR_NOT_ME;
  2127. resend = FALSE;
  2128. goto respond;
  2129. }
  2130. //
  2131. // Acquire the endpoint locks
  2132. //
  2133. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  2134. for ( i = 1; i < ENDPOINT_LOCK_COUNT; i++ ) {
  2135. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2136. }
  2137. tableHeader = &endpoint->ConnectionTable;
  2138. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  2139. connection = (PCONNECTION)tableHeader->Table[i].Owner;
  2140. if ( connection == NULL ) {
  2141. continue;
  2142. }
  2143. //
  2144. // Make sure this connection references an endpoint having
  2145. // the same netbios address that the new client is coming in on
  2146. //
  2147. // This is to allow a single server to be registered as more than
  2148. // one name on the network.
  2149. //
  2150. if( connection->Endpoint->TransportAddress.Length !=
  2151. endpoint->TransportAddress.Length ||
  2152. !RtlEqualMemory( connection->Endpoint->TransportAddress.Buffer,
  2153. endpoint->TransportAddress.Buffer,
  2154. endpoint->TransportAddress.Length ) ) {
  2155. //
  2156. // This connection is for an endpoint having a different network
  2157. // name than we have. Ignore it.
  2158. //
  2159. continue;
  2160. }
  2161. //
  2162. // Check the IPX address of the sender against this
  2163. // connection.
  2164. //
  2165. if ( RtlEqualMemory(
  2166. &connection->IpxAddress,
  2167. &sourceAddress->Address[0].Address[0],
  2168. sizeof(TDI_ADDRESS_IPX) ) ) {
  2169. //
  2170. // The IPX addresses match. Check the machine name.
  2171. //
  2172. if ( !RtlEqualMemory(
  2173. connection->OemClientMachineName,
  2174. clientName,
  2175. SMB_IPX_NAME_LENGTH) ) {
  2176. //
  2177. // The connection is for a different machine name.
  2178. // Mark it as no longer valid. It will be killed
  2179. // when the Negotiate SMB is processed.
  2180. //
  2181. IF_DEBUG(IPX)KdPrint(("SRVIPX: Found stale connection %p\n", connection ));
  2182. connection->IpxAddress.Socket = 0;
  2183. break;
  2184. } else if ( connection->SequenceNumber != 0 ) {
  2185. ULONG timeNow;
  2186. SET_SERVER_TIME( connection->CurrentWorkQueue );
  2187. GET_SERVER_TIME( connection->CurrentWorkQueue, &timeNow );
  2188. //
  2189. // If the connection was initialized less than 5 seconds ago,
  2190. // then we must be processing a duplicate negotiate request.
  2191. //
  2192. timeNow -= connection->StartupTime;
  2193. if ( timeNow > SrvFiveSecondTickCount ) {
  2194. //
  2195. // The connection has been active for more than 5 seconds.
  2196. // Mark it as no longer valid. It will be killed when
  2197. // the Negotiate SMB is processed.
  2198. //
  2199. IF_DEBUG(IPX) KdPrint(( "SRVIPX: found stale connection %p\n", connection ));
  2200. connection->IpxAddress.Socket = 0;
  2201. break;
  2202. } else {
  2203. //
  2204. // Don't bother replying to avoid confusing the client.
  2205. //
  2206. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2207. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2208. }
  2209. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2210. SrvDereferenceEndpoint( endpoint );
  2211. goto return_workitem;
  2212. }
  2213. }
  2214. //
  2215. // The connection is still in the initializing state and
  2216. // the names match, so handle this as a lost response.
  2217. //
  2218. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Found initializing connection %p\n", connection ));
  2219. SmbPutUshort( &header->Sid, connection->Sid ); // NOT Aligned
  2220. goto duplicate_request;
  2221. } else {
  2222. IF_DEBUG(IPX) {
  2223. KdPrint(( " skipping index %x: different address\n", i ));
  2224. }
  2225. }
  2226. }
  2227. //
  2228. // Release the endpoint locks
  2229. //
  2230. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2231. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2232. }
  2233. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2234. //
  2235. // Get a free connection. If successful, the workcontext block will
  2236. // reference the connection block.
  2237. //
  2238. connection = GetIpxConnection(
  2239. WorkContext,
  2240. endpoint,
  2241. &sourceAddress->Address[0].Address[0],
  2242. clientName
  2243. );
  2244. //
  2245. // Now that we've gotten a connection structure for this endpoint,
  2246. // we can drop the reference we obtained above.
  2247. //
  2248. SrvDereferenceEndpoint( endpoint );
  2249. if ( connection == NULL ) {
  2250. //
  2251. // Unable to get a free connection.
  2252. //
  2253. goto return_workitem;
  2254. }
  2255. //
  2256. // Modify the FSP restart routine so that we can clean up stale
  2257. // connections.
  2258. //
  2259. IpxRestartReceive(WorkContext);
  2260. return;
  2261. duplicate_request:
  2262. //
  2263. // This is a duplicate request. If it's still being processed,
  2264. // indicate that to the client.
  2265. //
  2266. if ( connection->LastResponseLength == (USHORT)-1 ) {
  2267. IF_DEBUG(IPX) KdPrint(( "SRVIPX: request in progress\n" ));
  2268. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2269. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2270. }
  2271. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2272. error = SMB_ERR_WORKING;
  2273. resend = FALSE;
  2274. goto respond;
  2275. }
  2276. //
  2277. // The request has already been completed. Resend the response.
  2278. //
  2279. IF_DEBUG(IPX) KdPrint(( "SRVIPX: resending response\n" ));
  2280. resend = TRUE;
  2281. respond:
  2282. params = (PSMB_PARAMS)(header + 1);
  2283. header->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  2284. //
  2285. // Format the parameters portion of the SMB, and set the status.
  2286. //
  2287. if ( !resend ) {
  2288. SmbPutUshort( &header->Status.DosError.Error, error );
  2289. header->Status.DosError.ErrorClass = SMB_ERR_CLASS_SERVER;
  2290. header->Status.DosError.Reserved = 0;
  2291. params->WordCount = 0;
  2292. SmbPutUshort( &params->ByteCount, 0 );
  2293. length = sizeof(NT_SMB_HEADER) + sizeof(SMB_PARAMS);
  2294. } else {
  2295. //
  2296. // Copy the saved response data into the response.
  2297. //
  2298. SmbPutUlong( &header->Status.NtStatus, connection->LastResponseStatus );
  2299. RtlCopyMemory(
  2300. (PVOID)params,
  2301. connection->LastResponse,
  2302. connection->LastResponseLength
  2303. );
  2304. length = sizeof(NT_SMB_HEADER) + connection->LastResponseLength;
  2305. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2306. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2307. }
  2308. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2309. }
  2310. WorkContext->ResponseBuffer->DataLength = length;
  2311. WorkContext->ResponseBuffer->Mdl->ByteCount = length;
  2312. //
  2313. // Give up the reference we earlier obtained
  2314. //
  2315. SrvDereferenceEndpoint( endpoint );
  2316. //
  2317. // Send the packet.
  2318. //
  2319. DEBUG WorkContext->FsdRestartRoutine = NULL;
  2320. StartSendNoConnection( WorkContext, FALSE, TRUE );
  2321. return;
  2322. return_workitem:
  2323. //
  2324. // Dereference the work item manually.
  2325. //
  2326. ASSERT( WorkContext->BlockHeader.ReferenceCount == 1 );
  2327. WorkContext->BlockHeader.ReferenceCount = 0;
  2328. WorkContext->Endpoint = NULL;
  2329. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2330. WorkContext->FspRestartRoutine = SrvRestartReceive;
  2331. WorkContext->Irp->Cancel = FALSE;
  2332. WorkContext->ProcessingCount = 0;
  2333. RETURN_FREE_WORKITEM( WorkContext );
  2334. return;
  2335. } // IpxRestartNegotiate
  2336. VOID SRVFASTCALL
  2337. SrvIpxFastRestartRead (
  2338. IN OUT PWORK_CONTEXT WorkContext
  2339. )
  2340. /*++
  2341. Routine Description:
  2342. Implements core read over ipx.
  2343. Arguments:
  2344. WorkContext - Supplies a pointer to the work context block
  2345. describing server-specific context for the request.
  2346. Return Value:
  2347. None.
  2348. --*/
  2349. {
  2350. PREQ_READ request;
  2351. PRESP_READ response;
  2352. PRFCB rfcb;
  2353. PLFCB lfcb;
  2354. PCHAR readAddress;
  2355. CLONG readLength;
  2356. LARGE_INTEGER offset;
  2357. ULONG key;
  2358. PSMB_HEADER header;
  2359. PAGED_CODE( );
  2360. request = (PREQ_READ)WorkContext->RequestParameters;
  2361. response = (PRESP_READ)WorkContext->ResponseParameters;
  2362. //
  2363. // Store in the work context block the time at which processing
  2364. // of the request began. Use the time that the work item was
  2365. // queued to the FSP for this purpose.
  2366. //
  2367. WorkContext->StartTime = WorkContext->Timestamp;
  2368. //
  2369. // Update the server network error count.
  2370. //
  2371. SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE );
  2372. //
  2373. // We have received an SMB.
  2374. //
  2375. rfcb = WorkContext->Rfcb;
  2376. //
  2377. // Form the lock key using the FID and the PID.
  2378. //
  2379. // *** The FID must be included in the key in order to account for
  2380. // the folding of multiple remote compatibility mode opens into
  2381. // a single local open.
  2382. //
  2383. key = rfcb->ShiftedFid |
  2384. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2385. lfcb = rfcb->Lfcb;
  2386. //
  2387. // See if the direct host IPX smart card can handle this read. If so,
  2388. // return immediately, and the card will call our restart routine at
  2389. // SrvIpxSmartCardReadComplete
  2390. //
  2391. if( rfcb->PagedRfcb->IpxSmartCardContext ) {
  2392. IF_DEBUG( SIPX ) {
  2393. KdPrint(( "SrvIpxFastRestartRead: calling SmartCard Read for context %p\n",
  2394. WorkContext ));
  2395. }
  2396. WorkContext->Parameters.SmartCardRead.MdlReadComplete = lfcb->MdlReadComplete;
  2397. WorkContext->Parameters.SmartCardRead.DeviceObject = lfcb->DeviceObject;
  2398. if( SrvIpxSmartCard.Read( WorkContext->RequestBuffer->Buffer,
  2399. rfcb->PagedRfcb->IpxSmartCardContext,
  2400. key,
  2401. WorkContext ) == TRUE ) {
  2402. IF_DEBUG( SIPX ) {
  2403. KdPrint(( " SrvIpxFastRestartRead: SmartCard Read returns TRUE\n" ));
  2404. }
  2405. return;
  2406. }
  2407. IF_DEBUG( SIPX ) {
  2408. KdPrint(( " SrvIpxFastRestartRead: SmartCard Read returns FALSE\n" ));
  2409. }
  2410. }
  2411. IF_SMB_DEBUG(READ_WRITE1) {
  2412. KdPrint(( "Read request; FID 0x%lx, count %ld, offset %ld\n",
  2413. rfcb->Fid, SmbGetUshort( &request->Count ),
  2414. SmbGetUlong( &request->Offset ) ));
  2415. }
  2416. //
  2417. // Initialize the error class and code fields in the header to
  2418. // indicate success.
  2419. //
  2420. header = WorkContext->ResponseHeader;
  2421. SmbPutUlong( &header->ErrorClass, STATUS_SUCCESS );
  2422. //
  2423. // Determine the maximum amount of data we can read. This is the
  2424. // minimum of the amount requested by the client and the amount of
  2425. // room left in the response buffer. (Note that even though we may
  2426. // use an MDL read, the read length is still limited to the size of
  2427. // an SMB buffer.)
  2428. //
  2429. readAddress = (PCHAR)response->Buffer;
  2430. readLength = (ULONG)MIN(
  2431. (CLONG)SmbGetUshort( &request->Count ),
  2432. WorkContext->ResponseBuffer->BufferLength -
  2433. (readAddress - (PCHAR)header)
  2434. );
  2435. //
  2436. // Get the file offset.
  2437. //
  2438. offset.QuadPart = SmbGetUlong( &request->Offset );
  2439. //
  2440. // Try the fast I/O path first. If that fails, fall through to the
  2441. // normal build-an-IRP path.
  2442. //
  2443. if ( lfcb->FastIoRead != NULL ) {
  2444. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  2445. try {
  2446. if ( lfcb->FastIoRead(
  2447. lfcb->FileObject,
  2448. &offset,
  2449. readLength,
  2450. TRUE,
  2451. key,
  2452. readAddress,
  2453. &WorkContext->Irp->IoStatus,
  2454. lfcb->DeviceObject
  2455. ) ) {
  2456. //
  2457. // The fast I/O path worked. Call the restart routine directly
  2458. // to do postprocessing (including sending the response).
  2459. //
  2460. SrvFsdRestartRead( WorkContext );
  2461. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvIpxFastRestartRead complete.\n" ));
  2462. return;
  2463. }
  2464. }
  2465. except( EXCEPTION_EXECUTE_HANDLER ) {
  2466. // Fall through to the slow path on an exception
  2467. NTSTATUS status = GetExceptionCode();
  2468. IF_DEBUG(ERRORS) {
  2469. KdPrint(("FastIoRead threw exception %x\n", status ));
  2470. }
  2471. }
  2472. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  2473. }
  2474. //
  2475. // The turbo path failed. Build the read request, reusing the
  2476. // receive IRP.
  2477. //
  2478. //
  2479. // Note that we never do MDL reads here. The reasoning behind
  2480. // this is that because the read is going into an SMB buffer, it
  2481. // can't be all that large (by default, no more than 4K bytes),
  2482. // so the difference in cost between copy and MDL is minimal; in
  2483. // fact, copy read is probably faster than MDL read.
  2484. //
  2485. // Build an MDL describing the read buffer. Note that if the
  2486. // file system can complete the read immediately, the MDL isn't
  2487. // really needed, but if the file system must send the request
  2488. // to its FSP, the MDL _is_ needed.
  2489. //
  2490. // *** Note the assumption that the response buffer already has
  2491. // a valid full MDL from which a partial MDL can be built.
  2492. //
  2493. IoBuildPartialMdl(
  2494. WorkContext->ResponseBuffer->Mdl,
  2495. WorkContext->ResponseBuffer->PartialMdl,
  2496. readAddress,
  2497. readLength
  2498. );
  2499. //
  2500. // Build the IRP.
  2501. //
  2502. SrvBuildReadOrWriteRequest(
  2503. WorkContext->Irp, // input IRP address
  2504. lfcb->FileObject, // target file object address
  2505. WorkContext, // context
  2506. IRP_MJ_READ, // major function code
  2507. 0, // minor function code
  2508. readAddress, // buffer address
  2509. readLength, // buffer length
  2510. WorkContext->ResponseBuffer->PartialMdl, // MDL address
  2511. offset, // byte offset
  2512. key // lock key
  2513. );
  2514. IF_SMB_DEBUG(READ_WRITE2) {
  2515. KdPrint(( "SrvIpxFastRestartRead: copy read from file 0x%p, offset %ld, length %ld, destination 0x%p\n",
  2516. lfcb->FileObject, offset.LowPart, readLength,
  2517. readAddress ));
  2518. }
  2519. //
  2520. // Load the restart routine address and pass the request to the file
  2521. // system.
  2522. //
  2523. WorkContext->FsdRestartRoutine = SrvFsdRestartRead;
  2524. DEBUG WorkContext->FspRestartRoutine = NULL;
  2525. WorkContext->Irp->Cancel = FALSE;
  2526. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2527. //
  2528. // The read has been started. Control will return to the restart
  2529. // routine when the read completes.
  2530. //
  2531. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvIpxFastRestartRead complete.\n" ));
  2532. return;
  2533. } // SrvIpxFastRestartRead
  2534. BOOLEAN
  2535. SetupIpxFastCoreRead (
  2536. IN OUT PWORK_CONTEXT WorkContext
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. Prepares the workitem for the fast restart read by validating the
  2541. smb and verifying the fid.
  2542. Arguments:
  2543. WorkContext
  2544. Return Value:
  2545. TRUE, if rfcb referenced.
  2546. FALSE, otherwise.
  2547. --*/
  2548. {
  2549. PREQ_READ request;
  2550. PRESP_READ response;
  2551. NTSTATUS status;
  2552. BOOLEAN validSmb;
  2553. USHORT fid;
  2554. PRFCB rfcb;
  2555. UCHAR wordCount;
  2556. USHORT byteCount;
  2557. PSMB_USHORT byteCountPtr;
  2558. ULONG availableSpaceForSmb;
  2559. ULONG smbLength;
  2560. PSMB_HEADER header;
  2561. PSMB_PARAMS params;
  2562. PCONNECTION connection;
  2563. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  2564. request = (PREQ_READ)WorkContext->RequestParameters;
  2565. response = (PRESP_READ)WorkContext->ResponseParameters;
  2566. IF_SMB_DEBUG(READ_WRITE1) {
  2567. KdPrint(( "Read request; FID 0x%lx, count %ld, offset %ld\n",
  2568. SmbGetUshort( &request->Fid ), SmbGetUshort( &request->Count ),
  2569. SmbGetUlong( &request->Offset ) ));
  2570. }
  2571. //
  2572. // Validate this smb.
  2573. //
  2574. header = WorkContext->RequestHeader;
  2575. params = (PVOID)(header + 1);
  2576. smbLength = WorkContext->RequestBuffer->DataLength;
  2577. wordCount = *((PUCHAR)params);
  2578. byteCountPtr = (PSMB_USHORT)( (PCHAR)params +
  2579. sizeof(UCHAR) + (5 * sizeof(USHORT)) );
  2580. byteCount = SmbGetUshort( (PSMB_USHORT)( (PCHAR)params +
  2581. sizeof(UCHAR) + (5 * sizeof(USHORT))) );
  2582. availableSpaceForSmb = smbLength - sizeof(SMB_HEADER);
  2583. //
  2584. // Validate the Read smb.
  2585. //
  2586. validSmb = (SmbGetUlong((PULONG)header->Protocol) == SMB_HEADER_PROTOCOL)
  2587. &&
  2588. ((CHAR)wordCount == 5)
  2589. &&
  2590. ((PCHAR)byteCountPtr <= (PCHAR)header + smbLength -
  2591. sizeof(USHORT))
  2592. &&
  2593. ((5*sizeof(USHORT) + sizeof(UCHAR) + sizeof(USHORT) +
  2594. byteCount) <= availableSpaceForSmb);
  2595. if ( validSmb ) {
  2596. PTABLE_HEADER tableHeader;
  2597. USHORT index;
  2598. USHORT sequence;
  2599. //
  2600. // Verify the FID. If verified, the RFCB is referenced and
  2601. // its address is stored in the WorkContext block, and the RFCB
  2602. // address is returned.
  2603. //
  2604. fid = SmbGetUshort( &request->Fid );
  2605. //
  2606. // Initialize local variables: obtain the connection block address
  2607. // and crack the FID into its components.
  2608. //
  2609. connection = WorkContext->Connection;
  2610. //
  2611. // Acquire the spin lock that guards the connection's file table.
  2612. //
  2613. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2614. //
  2615. // See if this is the cached rfcb
  2616. //
  2617. if ( connection->CachedFid == (ULONG)fid ) {
  2618. rfcb = connection->CachedRfcb;
  2619. } else {
  2620. //
  2621. // Verify that the FID is in range, is in use, and has the correct
  2622. // sequence number.
  2623. index = FID_INDEX( fid );
  2624. sequence = FID_SEQUENCE( fid );
  2625. tableHeader = &connection->FileTable;
  2626. if ( (index >= (USHORT)tableHeader->TableSize) ||
  2627. (tableHeader->Table[index].Owner == NULL) ||
  2628. (tableHeader->Table[index].SequenceNumber != sequence) ) {
  2629. goto error_exit_locked;
  2630. }
  2631. rfcb = tableHeader->Table[index].Owner;
  2632. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  2633. goto error_exit_locked;
  2634. }
  2635. //
  2636. // If the caller wants to fail when there is a write behind
  2637. // error and the error exists, fill in NtStatus and do not
  2638. // return the RFCB pointer.
  2639. //
  2640. //
  2641. // !!! For now, we ignore write behind errors. Need to
  2642. // figure out how to translate the saved NT status to a
  2643. // DOS status...
  2644. //
  2645. #if 0
  2646. if ( !NT_SUCCESS(rfcb->SavedError) ) {
  2647. goto error_exit_locked;
  2648. }
  2649. #endif
  2650. //
  2651. // Cache the fid.
  2652. //
  2653. connection->CachedRfcb = rfcb;
  2654. connection->CachedFid = (ULONG)fid;
  2655. //
  2656. // The FID is valid within the context of this connection. Verify
  2657. // that the owning tree connect's TID is correct.
  2658. //
  2659. // Do not verify the UID for clients that do not understand it.
  2660. //
  2661. if ( (rfcb->Tid != SmbGetAlignedUshort(&header->Tid)) ||
  2662. (rfcb->Uid != SmbGetAlignedUshort(&header->Uid)) ) {
  2663. goto error_exit_locked;
  2664. }
  2665. }
  2666. //
  2667. // The file is active and the TID is valid. Reference the
  2668. // RFCB. Release the spin lock (we don't need it anymore).
  2669. //
  2670. rfcb->BlockHeader.ReferenceCount++;
  2671. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  2672. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2673. //
  2674. // Save the RFCB address in the work context block and
  2675. // return the file address.
  2676. //
  2677. WorkContext->Rfcb = rfcb;
  2678. ASSERT( GET_BLOCK_TYPE( rfcb->Mfcb ) == BlockTypeMfcb );
  2679. //
  2680. // Mark the rfcb as active
  2681. //
  2682. rfcb->IsActive = TRUE;
  2683. //
  2684. // Verify that the client has read access to the file via the
  2685. // specified handle.
  2686. //
  2687. if ( rfcb->ReadAccessGranted ) {
  2688. return(TRUE);
  2689. } else {
  2690. CHECK_PAGING_IO_ACCESS(
  2691. WorkContext,
  2692. rfcb->GrantedAccess,
  2693. &status );
  2694. if ( NT_SUCCESS( status ) ) {
  2695. return(TRUE);
  2696. }
  2697. }
  2698. }
  2699. return(FALSE);
  2700. error_exit_locked:
  2701. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2702. return(FALSE);
  2703. } // SetupIpxFastCoreRead
  2704. VOID
  2705. SrvFreeIpxConnectionInIndication(
  2706. IN PWORK_CONTEXT WorkContext
  2707. )
  2708. {
  2709. PCONNECTION connection = WorkContext->Connection;
  2710. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  2711. SrvRemoveEntryList(
  2712. &connection->InProgressWorkItemList,
  2713. &WorkContext->InProgressListEntry
  2714. );
  2715. connection->InProgressWorkContextCount--;
  2716. if ( --connection->BlockHeader.ReferenceCount == 0 ) {
  2717. connection->BlockHeader.ReferenceCount++;
  2718. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  2719. //
  2720. // Orphaned. Send to Boys Town.
  2721. //
  2722. DispatchToOrphanage( (PVOID)connection );
  2723. } else {
  2724. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  2725. }
  2726. WorkContext->Connection = NULL;
  2727. return;
  2728. } // SrvFreeIpxConnectionInIndication
  2729. VOID
  2730. SrvIpxSmartCardReadComplete(
  2731. IN PVOID Context,
  2732. IN PFILE_OBJECT FileObject,
  2733. IN PMDL Mdl OPTIONAL,
  2734. IN ULONG Length
  2735. )
  2736. /*++
  2737. Routine Description:
  2738. Completes the Read performed by an optional smart card that handles
  2739. direct host IPX clients.
  2740. Arguments:
  2741. Context - the WorkContext of the original request
  2742. FileObject - the file being read from
  2743. Mdl - the MDL chain obtained from the cache manager to satisfy the read
  2744. Length - the length of the read
  2745. Return Value:
  2746. None
  2747. --*/
  2748. {
  2749. PWORK_CONTEXT workContext = Context;
  2750. PRFCB rfcb = workContext->Rfcb;
  2751. UCHAR command = workContext->NextCommand;
  2752. LARGE_INTEGER position;
  2753. KIRQL oldIrql;
  2754. NTSTATUS status;
  2755. ASSERT( workContext != NULL );
  2756. ASSERT( FileObject != NULL );
  2757. ASSERT( command == SMB_COM_READ || command == SMB_COM_READ_MPX );
  2758. //
  2759. // Figure out the file position
  2760. //
  2761. if( command == SMB_COM_READ ) {
  2762. PREQ_READ readParms = (PREQ_READ)workContext->RequestParameters;
  2763. position.QuadPart = SmbGetUlong( &readParms->Offset ) + Length;
  2764. } else {
  2765. PREQ_READ_MPX readMpxParms = (PREQ_READ_MPX)workContext->RequestParameters;
  2766. position.QuadPart = SmbGetUlong( &readMpxParms->Offset ) + Length;
  2767. }
  2768. IF_DEBUG( SIPX ) {
  2769. KdPrint(( "SrvIpxSmartCardReadComplete: %s %p Length %u, New Position %u\n",
  2770. command==SMB_COM_READ ? "SMB_COM_READ" : "SMB_COM_READ_MPX",
  2771. Context, Length, position.LowPart ));
  2772. }
  2773. //
  2774. // Update the position info in the rfcb
  2775. //
  2776. rfcb->CurrentPosition = position.LowPart;
  2777. UPDATE_READ_STATS( workContext, Length );
  2778. UPDATE_STATISTICS( workContext, Length, command );
  2779. if( ARGUMENT_PRESENT( Mdl ) ) {
  2780. //
  2781. // Give the MDL chain back to the cache manager
  2782. //
  2783. if( workContext->Parameters.SmartCardRead.MdlReadComplete == NULL ||
  2784. workContext->Parameters.SmartCardRead.MdlReadComplete( FileObject,
  2785. Mdl,
  2786. workContext->Parameters.SmartCardRead.DeviceObject ) == FALSE ) {
  2787. //
  2788. // Fast path didn't work -- try the IRP way
  2789. //
  2790. position.QuadPart -= Length;
  2791. status = SrvIssueMdlCompleteRequest( workContext, NULL,
  2792. Mdl,
  2793. IRP_MJ_READ,
  2794. &position,
  2795. Length
  2796. );
  2797. if( !NT_SUCCESS( status ) ) {
  2798. //
  2799. // This is very bad, what else can we do?
  2800. //
  2801. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2802. }
  2803. }
  2804. }
  2805. //
  2806. // Finish the cleanup
  2807. //
  2808. if( command == SMB_COM_READ ) {
  2809. workContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  2810. SrvFsdRestartSmbAtSendCompletion( NULL, workContext->Irp, workContext );
  2811. } else {
  2812. SrvFsdRestartSmbComplete( workContext );
  2813. }
  2814. }