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

3780 lines
104 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 and
  861. // smbtrace not active
  862. //
  863. if ( writeMpx->Glomming &&
  864. ( BytesIndicated == BytesAvailable ) &&
  865. !SmbTraceActive[SMBTRACE_SERVER] ) {
  866. UCHAR wordCount;
  867. USHORT byteCount;
  868. PSMB_USHORT byteCountPtr;
  869. ULONG availableSpaceForSmb;
  870. header = (PNT_SMB_HEADER) Tsdu;
  871. params = (PVOID)(header + 1);
  872. wordCount = *((PUCHAR)params);
  873. byteCountPtr = (PSMB_USHORT)( (PCHAR)params +
  874. sizeof(UCHAR) + (12 * sizeof(USHORT)) );
  875. byteCount =
  876. SmbGetUshort( (PSMB_USHORT)( (PCHAR)params +
  877. sizeof(UCHAR) + (12 * sizeof(USHORT))) );
  878. availableSpaceForSmb = BytesIndicated - sizeof(SMB_HEADER);
  879. //
  880. // Validate the WriteMpx smb.
  881. //
  882. if ( (SmbGetUlong((PULONG)header->Protocol) == SMB_HEADER_PROTOCOL)
  883. &&
  884. ((CHAR)wordCount == 12)
  885. &&
  886. ((PCHAR)byteCountPtr <= (PCHAR)header + BytesIndicated -
  887. sizeof(USHORT))
  888. &&
  889. ((12*sizeof(USHORT) + sizeof(UCHAR) + sizeof(USHORT) +
  890. byteCount) <= availableSpaceForSmb) ) {
  891. //
  892. // The connection SpinLock is released in this routine.
  893. //
  894. if ( AddPacketToGlomInIndication(
  895. workContext,
  896. rfcb,
  897. Tsdu,
  898. BytesAvailable,
  899. ReceiveDatagramFlags,
  900. SourceAddress,
  901. Options
  902. ) ) {
  903. //
  904. // We need to clean up the connection.
  905. //
  906. goto return_connection;
  907. }
  908. KeLowerIrql( oldIrql );
  909. return(STATUS_SUCCESS);
  910. }
  911. }
  912. //
  913. // The file is active and the TID is valid. Reference the
  914. // RFCB.
  915. //
  916. rfcb->BlockHeader.ReferenceCount++;
  917. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  918. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  919. workContext->Parameters.WriteMpx.FirstPacketOfGlom = firstPacketOfGlom;
  920. //
  921. // Save the RFCB address in the work context block.
  922. //
  923. ASSERT( workContext->Rfcb == NULL );
  924. workContext->Rfcb = rfcb;
  925. //
  926. // Change the FSP restart routine for the work item to one
  927. // that's specific to Write Mpx. This is necessary in order
  928. // to do proper cleanup if a receive error occurs.
  929. //
  930. workContext->FspRestartRoutine = SrvRestartReceiveWriteMpx;
  931. goto start_receive;
  932. process_not_writempx:
  933. //
  934. // Reference the connection and save a pointer to it in the work
  935. // item.
  936. //
  937. ASSERT( connection != NULL );
  938. ASSERT( workContext != NULL );
  939. ASSERT( workContext->FsdRestartRoutine == SrvQueueWorkToFspAtDpcLevel );
  940. SrvReferenceConnectionLocked( connection );
  941. //
  942. // Put the work item on the in-progress list.
  943. //
  944. SrvInsertTailList(
  945. &connection->InProgressWorkItemList,
  946. &workContext->InProgressListEntry
  947. );
  948. connection->InProgressWorkContextCount++;
  949. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  950. //
  951. // Save the sender's IPX address.
  952. //
  953. workContext->Connection = connection;
  954. workContext->Endpoint = endpoint;
  955. workContext->ClientAddress->IpxAddress = *(PTA_IPX_ADDRESS)SourceAddress;
  956. workContext->ClientAddress->DatagramOptions =
  957. *(PIPX_DATAGRAM_OPTIONS)Options;
  958. if ( header->Command == SMB_COM_LOCKING_ANDX ) {
  959. //
  960. // If this is a Locking&X SMB that includes at least one unlock
  961. // request, we want to process the request quickly. So we put
  962. // it at the head of the work queue.
  963. //
  964. PREQ_LOCKING_ANDX request = (PREQ_LOCKING_ANDX)(header + 1);
  965. #if SRVDBG_PERF
  966. if( UnlocksGoFast )
  967. #endif
  968. if( (PCHAR)header + BytesIndicated >= (PCHAR)(&request->ByteCount) &&
  969. SmbGetUshort(&request->NumberOfUnlocks) != 0 ) {
  970. workContext->QueueToHead = TRUE;
  971. }
  972. } else if ( (header->Command == SMB_COM_READ) &&
  973. (BytesIndicated == BytesAvailable) ) {
  974. //
  975. // Copy the indicated data.
  976. //
  977. TdiCopyLookaheadData(
  978. workContext->RequestBuffer->Buffer,
  979. Tsdu,
  980. BytesIndicated,
  981. ReceiveDatagramFlags
  982. );
  983. workContext->RequestBuffer->DataLength = BytesIndicated;
  984. //
  985. // See if we are all set to do the fast path.
  986. //
  987. if ( SetupIpxFastCoreRead( workContext ) ) {
  988. workContext->FspRestartRoutine = SrvIpxFastRestartRead;
  989. workContext->ProcessingCount++;
  990. workQueue->stats.BytesReceived += BytesIndicated;
  991. //
  992. // Insert the work item at the tail of the nonblocking
  993. // work queue.
  994. //
  995. SrvInsertWorkQueueTail(
  996. workQueue,
  997. (PQUEUEABLE_BLOCK_HEADER)workContext
  998. );
  999. KeLowerIrql( oldIrql );
  1000. return STATUS_SUCCESS;
  1001. }
  1002. irp = workContext->Irp;
  1003. goto queue_to_fsp;
  1004. } else if ( (header->Command == SMB_COM_OPEN_ANDX) ||
  1005. (header->Command == SMB_COM_NT_CREATE_ANDX) ) {
  1006. //
  1007. // If this is an attempt to open a file, route the
  1008. // request to a blocking worker thread. This keeps opens
  1009. // out of the way of handle-based operations.
  1010. //
  1011. #if SRVDBG_PERF
  1012. if( OpensGoSlow )
  1013. #endif
  1014. {
  1015. workContext->FsdRestartRoutine = SrvQueueWorkToBlockingThread;
  1016. workQueue = &SrvBlockingWorkQueue;
  1017. }
  1018. } else if ( (header->Command == SMB_COM_CLOSE) ||
  1019. (header->Command == SMB_COM_FIND_CLOSE) ||
  1020. (header->Command == SMB_COM_FIND_CLOSE2) ) {
  1021. //
  1022. // Closing things is an operation that (1) releases resources, (2) is usually
  1023. // fast, and (3) can't be repeated indefinately by the client. Give the client
  1024. // a reward by putting it at the head of the queue.
  1025. //
  1026. workContext->QueueToHead = TRUE;
  1027. }
  1028. start_receive:
  1029. //
  1030. // If the SMB is completely within the indicated data, copy it
  1031. // directly into the buffer, avoiding the overhead of passing an IRP
  1032. // down to the transport.
  1033. //
  1034. irp = workContext->Irp;
  1035. if ( BytesIndicated == BytesAvailable ) {
  1036. //
  1037. // If this is a WRITE_MPX, and the buffer is big (how big is BIG?)
  1038. // and there is a TransportContext (indicating that we can take the
  1039. // NDIS buffer, then don't copy the data - just save the buffer
  1040. // address, length and transport context.
  1041. //
  1042. if ( BytesIndicated > SrvMaxCopyLength &&
  1043. header->Command == SMB_COM_WRITE_MPX &&
  1044. TransportContext ) {
  1045. workContext->Parameters.WriteMpx.Buffer = Tsdu;
  1046. workContext->Parameters.WriteMpx.ReceiveDatagramFlags =
  1047. ReceiveDatagramFlags;
  1048. workContext->Parameters.WriteMpx.TransportContext = TransportContext;
  1049. DEBUG *BytesTaken = BytesIndicated;
  1050. ASSERT( BytesIndicated >= MPX_HEADER_SIZE );
  1051. TdiCopyLookaheadData(
  1052. workContext->RequestBuffer->Buffer,
  1053. Tsdu,
  1054. MPX_HEADER_SIZE,
  1055. ReceiveDatagramFlags
  1056. );
  1057. status = STATUS_PENDING;
  1058. } else {
  1059. TdiCopyLookaheadData(
  1060. workContext->RequestBuffer->Buffer,
  1061. Tsdu,
  1062. BytesIndicated,
  1063. ReceiveDatagramFlags
  1064. );
  1065. // NB: status is set to STATUS_SUCCESS above!
  1066. }
  1067. #if SRVDBG_PERF
  1068. if ( Trap512s ) {
  1069. if ( header->Command == SMB_COM_READ ) {
  1070. PREQ_READ request = (PREQ_READ)(header + 1);
  1071. if ( (SmbGetUshort(&request->Count) == 512) &&
  1072. ((SmbGetUlong(&request->Offset) & 511) == 0) ) {
  1073. PRESP_READ response;
  1074. if (Break512s) DbgBreakPoint();
  1075. Trapped512s++;
  1076. response = (PRESP_READ)workContext->ResponseParameters;
  1077. response->WordCount = 5;
  1078. SmbPutUshort( &response->Count, 512 );
  1079. RtlZeroMemory( (PVOID)&response->Reserved[0], sizeof(response->Reserved) );
  1080. SmbPutUshort(
  1081. &response->ByteCount,
  1082. (USHORT)(512 + FIELD_OFFSET(RESP_READ,Buffer[0]) -
  1083. FIELD_OFFSET(RESP_READ,BufferFormat))
  1084. );
  1085. response->BufferFormat = SMB_FORMAT_DATA;
  1086. SmbPutUshort( &response->DataLength, 512 );
  1087. workContext->ResponseParameters = NEXT_LOCATION(
  1088. response,
  1089. RESP_READ,
  1090. 512
  1091. );
  1092. SrvFsdSendResponse( workContext );
  1093. return STATUS_SUCCESS;
  1094. }
  1095. }
  1096. }
  1097. #endif // SRVDBG_PERF
  1098. queue_to_fsp:
  1099. //
  1100. // Pretend the transport completed an IRP by doing what the
  1101. // restart routine, which is known to be
  1102. // SrvQueueWorkToFspAtDpcLevel, would do.
  1103. //
  1104. irp->IoStatus.Status = STATUS_SUCCESS;
  1105. irp->IoStatus.Information = BytesIndicated;
  1106. irp->Cancel = FALSE;
  1107. //
  1108. // *** THE FOLLOWING IS COPIED FROM SrvQueueWorkToFspAtDpcLevel.
  1109. //
  1110. // Increment the processing count.
  1111. //
  1112. workContext->ProcessingCount++;
  1113. //
  1114. // Insert the work item into the work queue
  1115. //
  1116. if( workContext->QueueToHead ) {
  1117. SrvInsertWorkQueueHead(
  1118. workQueue,
  1119. (PQUEUEABLE_BLOCK_HEADER)workContext
  1120. );
  1121. } else {
  1122. SrvInsertWorkQueueTail(
  1123. workQueue,
  1124. (PQUEUEABLE_BLOCK_HEADER)workContext
  1125. );
  1126. }
  1127. KeLowerIrql( oldIrql );
  1128. return status;
  1129. }
  1130. build_irp:
  1131. //
  1132. // We can't copy the indicated data. Set up the receive IRP.
  1133. //
  1134. ASSERT( workQueue != NULL );
  1135. irp->Tail.Overlay.OriginalFileObject = NULL;
  1136. irp->Tail.Overlay.Thread = workQueue->IrpThread;
  1137. DEBUG irp->RequestorMode = KernelMode;
  1138. //
  1139. // Set up the completion routine.
  1140. //
  1141. IoSetCompletionRoutine(
  1142. irp,
  1143. SrvFsdIoCompletionRoutine,
  1144. workContext,
  1145. TRUE,
  1146. TRUE,
  1147. TRUE
  1148. );
  1149. //
  1150. // Make the next stack location current. Normally IoCallDriver
  1151. // would do this, but since we're bypassing that, we do it directly.
  1152. // Load the target device object address into the stack location.
  1153. // This especially important because the server likes to reuse IRPs.
  1154. //
  1155. // Get a pointer to the next stack location. This one is used to
  1156. // hold the parameters for the device I/O control request.
  1157. //
  1158. IoSetNextIrpStackLocation( irp );
  1159. irpSp = IoGetCurrentIrpStackLocation( irp );
  1160. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1161. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE_DATAGRAM;
  1162. //
  1163. // Copy the caller's parameters to the service-specific portion of the
  1164. // IRP for those parameters that are the same for all three methods.
  1165. //
  1166. requestBuffer = workContext->RequestBuffer;
  1167. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  1168. parameters->ReceiveLength = requestBuffer->BufferLength;
  1169. parameters->ReceiveFlags = 0;
  1170. irp->MdlAddress = requestBuffer->Mdl;
  1171. irp->AssociatedIrp.SystemBuffer = NULL;
  1172. irpSp->Flags = 0;
  1173. irpSp->DeviceObject = endpoint->DeviceObject;
  1174. irpSp->FileObject = endpoint->FileObject;
  1175. ASSERT( irp->StackCount >= irpSp->DeviceObject->StackSize );
  1176. //
  1177. // Return STATUS_MORE_PROCESSING_REQUIRED so that the transport
  1178. // provider will use our IRP to service the receive.
  1179. //
  1180. *IoRequestPacket = irp;
  1181. *BytesTaken = 0;
  1182. KeLowerIrql( oldIrql );
  1183. return STATUS_MORE_PROCESSING_REQUIRED;
  1184. bad_fid:
  1185. //
  1186. // An invalid FID was specified on a Write Mpx request, or there was
  1187. // a saved write behind error in the RFCB. If this is an
  1188. // unsequenced request, we drop it on the floor. If it's a
  1189. // sequenced request, we send an error response.
  1190. //
  1191. if ( sequenceNumber == 0 ) {
  1192. stale_mid:
  1193. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1194. goto return_connection;
  1195. }
  1196. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  1197. ASSERT( workContext->Connection != NULL );
  1198. SrvFreeIpxConnectionInIndication( workContext );
  1199. resend = FALSE;
  1200. goto respond;
  1201. duplicate_request:
  1202. //
  1203. // This is a duplicate request. If it's still being processed,
  1204. // indicate that to the client.
  1205. //
  1206. if ( connection->LastResponseLength == (USHORT)-1 ) {
  1207. IF_DEBUG(IPX) KdPrint(( "SRVIPX: request in progress\n" ));
  1208. if( connection->IpxDuplicateCount++ < connection->IpxDropDuplicateCount ) {
  1209. //
  1210. // We drop every few duplicate request from the client
  1211. //
  1212. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1213. KeLowerIrql( oldIrql );
  1214. return STATUS_SUCCESS;
  1215. }
  1216. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1217. connection->IpxDuplicateCount = 0;
  1218. error = SMB_ERR_WORKING;
  1219. resend = FALSE;
  1220. } else {
  1221. //
  1222. // The request has already been completed. Resend the response.
  1223. //
  1224. IF_DEBUG(IPX) KdPrint(( "SRVIPX: resending response\n" ));
  1225. resend = TRUE;
  1226. }
  1227. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  1228. if( workContext == NULL ) {
  1229. if( resend == TRUE ) {
  1230. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1231. }
  1232. KeLowerIrql( oldIrql );
  1233. InterlockedIncrement( &connection->CurrentWorkQueue->NeedWorkItem );
  1234. return STATUS_SUCCESS;
  1235. }
  1236. respond:
  1237. ASSERT( workContext != NULL );
  1238. //
  1239. // Copy the received SMB header into the response buffer.
  1240. //
  1241. RtlCopyMemory(
  1242. workContext->ResponseBuffer->Buffer,
  1243. header,
  1244. sizeof(NT_SMB_HEADER)
  1245. );
  1246. header = (PNT_SMB_HEADER)workContext->ResponseBuffer->Buffer;
  1247. params = (PSMB_PARAMS)(header + 1);
  1248. header->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  1249. //
  1250. // Format the parameters portion of the SMB, and set the status.
  1251. //
  1252. if ( !resend ) {
  1253. SmbPutUshort( &header->Status.DosError.Error, error );
  1254. header->Status.DosError.ErrorClass = SMB_ERR_CLASS_SERVER;
  1255. header->Status.DosError.Reserved = 0;
  1256. params->WordCount = 0;
  1257. SmbPutUshort( &params->ByteCount, 0 );
  1258. length = sizeof(NT_SMB_HEADER) + sizeof(SMB_PARAMS);
  1259. } else {
  1260. //
  1261. // Copy the saved response data into the response.
  1262. //
  1263. SmbPutUlong( &header->Status.NtStatus, connection->LastResponseStatus );
  1264. SmbPutUshort( &header->Tid, connection->LastTid);
  1265. SmbPutUshort( &header->Uid, connection->LastUid);
  1266. RtlCopyMemory(
  1267. (PVOID)params,
  1268. connection->LastResponse,
  1269. connection->LastResponseLength
  1270. );
  1271. length = sizeof(NT_SMB_HEADER) + connection->LastResponseLength;
  1272. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1273. }
  1274. workContext->ResponseBuffer->DataLength = length;
  1275. workContext->ResponseBuffer->Mdl->ByteCount = length;
  1276. //
  1277. // Format the destination address.
  1278. //
  1279. workContext->ClientAddress->IpxAddress = *(PTA_IPX_ADDRESS)SourceAddress;
  1280. workContext->ClientAddress->DatagramOptions =
  1281. *(PIPX_DATAGRAM_OPTIONS)Options;
  1282. //
  1283. // Send the packet.
  1284. //
  1285. workContext->Endpoint = endpoint;
  1286. DEBUG workContext->FsdRestartRoutine = NULL;
  1287. StartSendNoConnection( workContext, FALSE, TRUE );
  1288. KeLowerIrql( oldIrql );
  1289. return STATUS_SUCCESS;
  1290. return_connection:
  1291. SrvFreeIpxConnectionInIndication( workContext );
  1292. KeLowerIrql( oldIrql );
  1293. workContext->BlockHeader.ReferenceCount = 0;
  1294. RETURN_FREE_WORKITEM( workContext );
  1295. return STATUS_SUCCESS;
  1296. } // SrvIpxServerDatagramHandlerCommon
  1297. NTSTATUS
  1298. SrvIpxServerDatagramHandler (
  1299. IN PVOID TdiEventContext,
  1300. IN int SourceAddressLength,
  1301. IN PVOID SourceAddress,
  1302. IN int OptionsLength,
  1303. IN PVOID Options,
  1304. IN ULONG ReceiveDatagramFlags,
  1305. IN ULONG BytesIndicated,
  1306. IN ULONG BytesAvailable,
  1307. OUT ULONG *BytesTaken,
  1308. IN PVOID Tsdu,
  1309. OUT PIRP *IoRequestPacket
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. This is the receive datagram event handler for the IPX server socket.
  1314. It attempts to dequeue a preformatted work item from a list
  1315. anchored in the device object. If this is successful, it returns
  1316. the IRP associated with the work item to the transport provider to
  1317. be used to receive the data. Otherwise, the message is dropped.
  1318. Arguments:
  1319. TdiEventContext - Pointer to receiving endpoint
  1320. SourceAddressLength - Length of SourceAddress
  1321. SourceAddress - Address of sender
  1322. OptionsLength - Length of options
  1323. Options - Options for the receive
  1324. ReceiveDatagramFlags - Set of flags indicating the status of the
  1325. received message
  1326. BytesIndicated - Number of bytes in this indication (lookahead)
  1327. BytesAvailable - Number of bytes in the complete TSDU
  1328. BytesTaken - Returns the number of bytes taken by the handler
  1329. Tsdu - Pointer to buffer describing the Transport Service Data Unit
  1330. IoRequestPacket - Returns a pointer to I/O request packet, if the
  1331. returned status is STATUS_MORE_PROCESSING_REQUIRED. This IRP is
  1332. made the 'current' Receive for the endpoint.
  1333. Return Value:
  1334. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  1335. processed the request. If STATUS_MORE_PROCESSING_REQUIRED,
  1336. the Irp parameter points to a formatted Receive request to
  1337. be used to receive the data. If STATUS_DATA_NOT_ACCEPTED,
  1338. the message is lost.
  1339. --*/
  1340. {
  1341. NTSTATUS status;
  1342. status = SrvIpxServerDatagramHandlerCommon(
  1343. TdiEventContext,
  1344. SourceAddressLength,
  1345. SourceAddress,
  1346. OptionsLength,
  1347. Options,
  1348. ReceiveDatagramFlags,
  1349. BytesIndicated,
  1350. BytesAvailable,
  1351. BytesTaken,
  1352. Tsdu,
  1353. IoRequestPacket,
  1354. NULL
  1355. );
  1356. ASSERT( status != STATUS_PENDING );
  1357. return status;
  1358. } // SrvIpxServerDatagramHandler
  1359. NTSTATUS
  1360. SrvIpxServerChainedDatagramHandler (
  1361. IN PVOID TdiEventContext,
  1362. IN int SourceAddressLength,
  1363. IN PVOID SourceAddress,
  1364. IN int OptionsLength,
  1365. IN PVOID Options,
  1366. IN ULONG ReceiveDatagramFlags,
  1367. IN ULONG ReceiveDatagramLength,
  1368. IN ULONG StartingOffset,
  1369. IN PMDL Tsdu,
  1370. IN PVOID TransportContext
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This is the receive datagram event handler for the IPX server socket.
  1375. It attempts to dequeue a preformatted work item from a list
  1376. anchored in the device object. If this is successful, it returns
  1377. the IRP associated with the work item to the transport provider to
  1378. be used to receive the data. Otherwise, the message is dropped.
  1379. Arguments:
  1380. TdiEventContext - Pointer to receiving endpoint
  1381. SourceAddressLength - Length of SourceAddress
  1382. SourceAddress - Address of sender
  1383. OptionsLength - Length of options
  1384. Options - Options for the receive
  1385. ReceiveDatagramFlags - Set of flags indicating the status of the
  1386. received message
  1387. ReceiveDatagramLength - The length in byutes of the client data in the Tsdu
  1388. StartingOffset - Offset, in bytes, from beginning of Tsdu to client's data
  1389. Tsdu - Pointer to an MDL chain describing the received data
  1390. TranportContext - Context to be passed to TdiReturnChainedReceives if
  1391. buffer is taken
  1392. Return Value:
  1393. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  1394. processed the request. If STATUS_PENDING, the receive buffer was
  1395. taken and it will be returned via TdiReturnChainedReceives. If
  1396. If STATUS_DATA_NOT_ACCEPTED, the message is lost.
  1397. --*/
  1398. {
  1399. PVOID receiveBuffer;
  1400. ULONG bytesTaken;
  1401. NTSTATUS status;
  1402. PIRP ioRequestPacket = NULL;
  1403. ASSERT( StartingOffset < 512 );
  1404. receiveBuffer = (PCHAR)MmGetSystemAddressForMdl( Tsdu ) + StartingOffset;
  1405. status = SrvIpxServerDatagramHandlerCommon(
  1406. TdiEventContext,
  1407. SourceAddressLength,
  1408. SourceAddress,
  1409. OptionsLength,
  1410. Options,
  1411. ReceiveDatagramFlags,
  1412. ReceiveDatagramLength,
  1413. ReceiveDatagramLength,
  1414. &bytesTaken,
  1415. receiveBuffer,
  1416. &ioRequestPacket,
  1417. TransportContext
  1418. );
  1419. ASSERT( ioRequestPacket == NULL );
  1420. DEBUG if ( status == STATUS_PENDING ) {
  1421. ASSERT( bytesTaken == ReceiveDatagramLength );
  1422. }
  1423. return status;
  1424. } // SrvIpxServerChainedDatagramHandler
  1425. VOID
  1426. SrvIpxStartSend (
  1427. IN OUT PWORK_CONTEXT WorkContext,
  1428. IN PIO_COMPLETION_ROUTINE SendCompletionRoutine
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. This function sends an SMB/IPX name claim request or response. It
  1433. is started as an asynchronous I/O request. When the Send completes,
  1434. the restart routine preloaded into the work context is called.
  1435. Arguments:
  1436. WorkContext - Supplies a pointer to a Work Context block
  1437. Return Value:
  1438. None.
  1439. --*/
  1440. {
  1441. PENDPOINT endpoint;
  1442. PCONNECTION connection;
  1443. PTDI_REQUEST_KERNEL_SENDDG parameters;
  1444. PIO_STACK_LOCATION irpSp;
  1445. PIRP irp;
  1446. PMDL mdl;
  1447. ULONG sendLength;
  1448. USHORT responseLength;
  1449. PDEVICE_OBJECT deviceObject;
  1450. PFILE_OBJECT fileObject;
  1451. PTDI_CONNECTION_INFORMATION destination;
  1452. PNT_SMB_HEADER header;
  1453. // IF_DEBUG(IPX2) SrvPrint0( "SrvIpxStartSend entered\n" );
  1454. //
  1455. // Set ProcessingCount to zero so this send cannot be cancelled.
  1456. // This is used together with setting the cancel flag to false below.
  1457. //
  1458. // WARNING: This still presents us with a tiny window where this
  1459. // send could be cancelled.
  1460. //
  1461. WorkContext->ProcessingCount = 0;
  1462. //
  1463. // Count up the length of the data described by chained MDLs.
  1464. //
  1465. sendLength = WorkContext->ResponseBuffer->DataLength;
  1466. //
  1467. // Get the MDL pointer.
  1468. //
  1469. mdl = WorkContext->ResponseBuffer->Mdl;
  1470. //
  1471. // Build the I/O request packet.
  1472. //
  1473. // *** Note that the connection block is not referenced to account
  1474. // for this I/O request. The WorkContext block already has a
  1475. // referenced pointer to the connection, and this pointer is not
  1476. // dereferenced until after the I/O completes.
  1477. //
  1478. irp = WorkContext->Irp;
  1479. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1480. DEBUG irp->RequestorMode = KernelMode;
  1481. //
  1482. // Get a pointer to the next stack location. This one is used to
  1483. // hold the parameters for the device I/O control request.
  1484. //
  1485. irpSp = IoGetNextIrpStackLocation( irp );
  1486. //
  1487. // Set up the completion routine.
  1488. //
  1489. IoSetCompletionRoutine(
  1490. irp,
  1491. SendCompletionRoutine,
  1492. (PVOID)WorkContext,
  1493. TRUE,
  1494. TRUE,
  1495. TRUE
  1496. );
  1497. destination = &WorkContext->ClientAddress->Descriptor;
  1498. destination->UserDataLength = 0;
  1499. destination->OptionsLength = sizeof(IPX_DATAGRAM_OPTIONS);
  1500. destination->Options = &WorkContext->ClientAddress->DatagramOptions;
  1501. destination->RemoteAddressLength = sizeof(TA_IPX_ADDRESS);
  1502. destination->RemoteAddress = &WorkContext->ClientAddress->IpxAddress;
  1503. parameters = (PTDI_REQUEST_KERNEL_SENDDG)&irpSp->Parameters;
  1504. parameters->SendLength = sendLength;
  1505. parameters->SendDatagramInformation = destination;
  1506. endpoint = WorkContext->Endpoint;
  1507. ASSERT( endpoint->IsConnectionless );
  1508. deviceObject = endpoint->DeviceObject;
  1509. fileObject = endpoint->FileObject;
  1510. ASSERT( irp->StackCount >= deviceObject->StackSize );
  1511. irp->MdlAddress = mdl;
  1512. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1513. irpSp->FileObject = fileObject;
  1514. //
  1515. // If this is a sequenced message, save the response data.
  1516. //
  1517. header = (PNT_SMB_HEADER)WorkContext->ResponseHeader;
  1518. ASSERT( header != NULL );
  1519. connection = WorkContext->Connection;
  1520. ASSERT( connection != NULL );
  1521. if ( SmbGetAlignedUshort(&header->SequenceNumber) != 0 ) {
  1522. IF_DEBUG(IPX) {
  1523. KdPrint(("SRVIPX: Responding to sequenced request %x mid=%x, connection %p\n",
  1524. SmbGetAlignedUshort(&header->SequenceNumber),
  1525. SmbGetAlignedUshort(&header->Mid), connection ));
  1526. }
  1527. ASSERT( sendLength - sizeof(SMB_HEADER) < 0x10000 );
  1528. responseLength = (USHORT)(sendLength - sizeof(SMB_HEADER));
  1529. IF_DEBUG(IPX) {
  1530. KdPrint(("SRVIPX: parameters length %x, max=%x\n",
  1531. responseLength, MAX_SAVED_RESPONSE_LENGTH ));
  1532. }
  1533. if ( responseLength > MAX_SAVED_RESPONSE_LENGTH ) {
  1534. //
  1535. // The response is too large to save. The client shouldn't
  1536. // be doing this, except on transactions, for which we save
  1537. // a copy of the full response.
  1538. //
  1539. if ( (header->Command == SMB_COM_TRANSACTION) ||
  1540. (header->Command == SMB_COM_TRANSACTION_SECONDARY) ||
  1541. (header->Command == SMB_COM_TRANSACTION2) ||
  1542. (header->Command == SMB_COM_TRANSACTION2_SECONDARY) ) {
  1543. //
  1544. // We need a buffer to hold the response. If a buffer
  1545. // has already been allocated, and is large enough, use
  1546. // it. Otherwise, allocate one.
  1547. //
  1548. IF_DEBUG(IPX) {
  1549. KdPrint(("SRVIPX: transaction; saving long response\n" ));
  1550. }
  1551. if ( (connection->LastResponse == connection->BuiltinSavedResponse) ||
  1552. (connection->LastResponseBufferLength < responseLength) ) {
  1553. PVOID resp = ALLOCATE_NONPAGED_POOL( responseLength, BlockTypeDataBuffer );
  1554. if( resp != NULL ) {
  1555. if ( connection->LastResponse != connection->BuiltinSavedResponse ) {
  1556. IF_DEBUG(IPX) {
  1557. KdPrint(("SRVIPX: deallocating old response buffer %p\n",
  1558. connection->LastResponse ));
  1559. }
  1560. DEALLOCATE_NONPAGED_POOL( connection->LastResponse );
  1561. }
  1562. connection->LastResponse = resp;
  1563. IF_DEBUG(IPX) {
  1564. KdPrint(("SRVIPX: new response buffer %p\n",
  1565. connection->LastResponse ));
  1566. }
  1567. connection->LastResponseBufferLength = responseLength;
  1568. }
  1569. }
  1570. } else {
  1571. IF_DEBUG(IPX) {
  1572. KdPrint(("SRVIPX: not a transaction; illegal long response\n" ));
  1573. }
  1574. SmbPutUshort( &header->Status.DosError.Error, SMB_ERR_ERROR );
  1575. header->Status.DosError.ErrorClass = SMB_ERR_CLASS_SERVER;
  1576. header->Status.DosError.Reserved = 0;
  1577. *(PLONG)(header + 1) = 0; // set WCT and BCC to 0
  1578. sendLength = sizeof(SMB_HEADER) + sizeof(SMB_PARAMS);
  1579. responseLength = 3;
  1580. mdl->ByteCount = sendLength;
  1581. parameters->SendLength = sendLength;
  1582. goto small_response;
  1583. }
  1584. } else {
  1585. small_response:
  1586. //
  1587. // The response fits in the built-in buffer.
  1588. //
  1589. IF_DEBUG(IPX) {
  1590. KdPrint(("SRVIPX: response fits in builtin response buffer\n" ));
  1591. }
  1592. if ( connection->LastResponse != connection->BuiltinSavedResponse ) {
  1593. IF_DEBUG(IPX) {
  1594. KdPrint(("SRVIPX: deallocating old response buffer %p\n",
  1595. connection->LastResponse ));
  1596. }
  1597. DEALLOCATE_NONPAGED_POOL( connection->LastResponse );
  1598. connection->LastResponse = connection->BuiltinSavedResponse;
  1599. connection->LastResponseBufferLength = sizeof( connection->BuiltinSavedResponse );
  1600. }
  1601. }
  1602. //
  1603. // Save the response data in the connection.
  1604. //
  1605. connection->LastResponseStatus = SmbGetUlong( &header->Status.NtStatus );
  1606. connection->LastUid = SmbGetUshort( &header->Uid );
  1607. connection->LastTid = SmbGetUshort( &header->Tid );
  1608. connection->LastResponseLength = MIN( responseLength, connection->LastResponseBufferLength );
  1609. RtlCopyMemory( connection->LastResponse, (header + 1), connection->LastResponseLength );
  1610. } else {
  1611. IF_DEBUG(IPX) {
  1612. KdPrint(("SRVIPX: Responding to unsequenced request mid=%x\n",
  1613. SmbGetAlignedUshort(&header->Mid) ));
  1614. }
  1615. }
  1616. //
  1617. // If statistics are to be gathered for this work item, do so now.
  1618. //
  1619. UPDATE_STATISTICS(
  1620. WorkContext,
  1621. sendLength,
  1622. WorkContext->ResponseHeader->Command
  1623. );
  1624. //
  1625. // If SmbTrace is active and we're in a context where the SmbTrace
  1626. // shared section isn't accessible, send this off to the FSP.
  1627. //
  1628. if ( SmbTraceActive[SMBTRACE_SERVER] ) {
  1629. if ((KeGetCurrentIrql() == DISPATCH_LEVEL) ||
  1630. (IoGetCurrentProcess() != SrvServerProcess)) {
  1631. irp->AssociatedIrp.SystemBuffer = NULL;
  1632. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1633. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1634. irpSp->MinorFunction = TDI_SEND_DATAGRAM;
  1635. WorkContext->Parameters2.StartSend.FspRestartRoutine =
  1636. WorkContext->FspRestartRoutine;
  1637. WorkContext->Parameters2.StartSend.SendLength = sendLength;
  1638. WorkContext->FspRestartRoutine = RestartStartSend;
  1639. SrvQueueWorkToFsp( WorkContext );
  1640. return;
  1641. } else {
  1642. SMBTRACE_SRV( mdl );
  1643. }
  1644. }
  1645. //
  1646. // Pass the request to the transport provider.
  1647. //
  1648. //
  1649. // Increment the pending operation count
  1650. //
  1651. InterlockedIncrement( &WorkContext->Connection->OperationsPendingOnTransport );
  1652. //
  1653. // Set the cancel flag to FALSE in case this was cancelled by
  1654. // the SrvSmbNtCancel routine.
  1655. //
  1656. if ( endpoint->FastTdiSendDatagram ) {
  1657. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.DirectSendsAttempted );
  1658. DEBUG irpSp->DeviceObject = deviceObject;
  1659. irpSp->MinorFunction = TDI_DIRECT_SEND_DATAGRAM;
  1660. IoSetNextIrpStackLocation( irp );
  1661. irp->Cancel = FALSE;
  1662. endpoint->FastTdiSendDatagram( deviceObject, irp );
  1663. } else {
  1664. irp->AssociatedIrp.SystemBuffer = NULL;
  1665. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1666. irp->Cancel = FALSE;
  1667. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1668. irpSp->MinorFunction = TDI_SEND_DATAGRAM;
  1669. (VOID)IoCallDriver( deviceObject, irp );
  1670. }
  1671. return;
  1672. } // SrvIpxStartSend
  1673. VOID
  1674. StartSendNoConnection (
  1675. IN OUT PWORK_CONTEXT WorkContext,
  1676. IN BOOLEAN UseNameSocket,
  1677. IN BOOLEAN LocalTargetValid
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. This function sends an SMB/IPX name claim request or response. It
  1682. is started as an asynchronous I/O request. When the Send completes,
  1683. the restart routine preloaded into the work context is called.
  1684. Arguments:
  1685. WorkContext - Supplies a pointer to a Work Context block
  1686. UseNameSocket - Indicates whether the name socket or the server
  1687. socket is to be used.
  1688. Return Value:
  1689. None.
  1690. --*/
  1691. {
  1692. PENDPOINT endpoint;
  1693. PTDI_REQUEST_KERNEL_SENDDG parameters;
  1694. PIO_STACK_LOCATION irpSp;
  1695. PIRP irp;
  1696. ULONG sendLength;
  1697. PDEVICE_OBJECT deviceObject;
  1698. PFILE_OBJECT fileObject;
  1699. PTDI_CONNECTION_INFORMATION destination;
  1700. //
  1701. // Set ProcessingCount to zero so this send cannot be cancelled.
  1702. // This is used together with setting the cancel flag to false below.
  1703. //
  1704. // WARNING: This still presents us with a tiny window where this
  1705. // send could be cancelled.
  1706. //
  1707. WorkContext->ProcessingCount = 0;
  1708. //
  1709. // Count up the length of the data described by chained MDLs.
  1710. //
  1711. sendLength = WorkContext->ResponseBuffer->DataLength;
  1712. //
  1713. // Build the I/O request packet.
  1714. //
  1715. // *** Note that the connection block is not referenced to account
  1716. // for this I/O request. The WorkContext block already has a
  1717. // referenced pointer to the connection, and this pointer is not
  1718. // dereferenced until after the I/O completes.
  1719. //
  1720. irp = WorkContext->Irp;
  1721. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1722. DEBUG irp->RequestorMode = KernelMode;
  1723. //
  1724. // Get a pointer to the next stack location. This one is used to
  1725. // hold the parameters for the device I/O control request.
  1726. //
  1727. irpSp = IoGetNextIrpStackLocation( irp );
  1728. //
  1729. // Set up the completion routine.
  1730. //
  1731. IoSetCompletionRoutine(
  1732. irp,
  1733. RequeueIpxWorkItemAtSendCompletion,
  1734. (PVOID)WorkContext,
  1735. TRUE,
  1736. TRUE,
  1737. TRUE
  1738. );
  1739. destination = &WorkContext->ClientAddress->Descriptor;
  1740. destination->UserDataLength = 0;
  1741. destination->OptionsLength =
  1742. LocalTargetValid ? sizeof(IPX_DATAGRAM_OPTIONS) : sizeof(UCHAR);
  1743. ASSERT( FIELD_OFFSET( IPX_DATAGRAM_OPTIONS, PacketType ) == 0 );
  1744. destination->Options = &WorkContext->ClientAddress->DatagramOptions;
  1745. destination->RemoteAddressLength = sizeof(TA_IPX_ADDRESS);
  1746. destination->RemoteAddress = &WorkContext->ClientAddress->IpxAddress;
  1747. parameters = (PTDI_REQUEST_KERNEL_SENDDG)&irpSp->Parameters;
  1748. parameters->SendLength = sendLength;
  1749. parameters->SendDatagramInformation = destination;
  1750. irp->MdlAddress = WorkContext->ResponseBuffer->Mdl;
  1751. endpoint = WorkContext->Endpoint;
  1752. ASSERT( endpoint->IsConnectionless );
  1753. if ( !UseNameSocket ) {
  1754. deviceObject = endpoint->DeviceObject;
  1755. fileObject = endpoint->FileObject;
  1756. } else {
  1757. deviceObject = endpoint->NameSocketDeviceObject;
  1758. fileObject = endpoint->NameSocketFileObject;
  1759. }
  1760. ASSERT( irp->StackCount >= deviceObject->StackSize );
  1761. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1762. irpSp->FileObject = fileObject;
  1763. //
  1764. // Pass the request to the transport provider.
  1765. //
  1766. //
  1767. // Set the cancel flag to FALSE in case this was cancelled by
  1768. // the SrvSmbNtCancel routine.
  1769. //
  1770. irp->Cancel = FALSE;
  1771. if ( endpoint->FastTdiSendDatagram ) {
  1772. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.DirectSendsAttempted );
  1773. DEBUG irpSp->DeviceObject = deviceObject;
  1774. irpSp->MinorFunction = TDI_DIRECT_SEND_DATAGRAM;
  1775. IoSetNextIrpStackLocation( irp );
  1776. endpoint->FastTdiSendDatagram( deviceObject, irp );
  1777. } else {
  1778. irp->AssociatedIrp.SystemBuffer = NULL;
  1779. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1780. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1781. irpSp->MinorFunction = TDI_SEND_DATAGRAM;
  1782. (VOID)IoCallDriver( deviceObject, irp );
  1783. }
  1784. return;
  1785. } // StartSendNoConnection
  1786. VOID SRVFASTCALL
  1787. IpxRestartReceive (
  1788. IN OUT PWORK_CONTEXT WorkContext
  1789. )
  1790. /*++
  1791. Routine Description:
  1792. This is the restart routine for IPX Receive completion. It does
  1793. some IPX-specific setup work, then calls SrvRestartReceive.
  1794. Arguments:
  1795. WorkContext - Supplies a pointer to the work context block
  1796. describing server-specific context for the request.
  1797. Return Value:
  1798. None.
  1799. --*/
  1800. {
  1801. PSMB_HEADER header = (PSMB_HEADER)WorkContext->RequestBuffer->Buffer;
  1802. PAGED_CODE( );
  1803. ASSERT( header->Command == SMB_COM_NEGOTIATE );
  1804. //
  1805. // Get rid of stale connections.
  1806. //
  1807. IF_DEBUG(IPX) KdPrint(( "SRVIPX: processing Negotiate\n" ));
  1808. PurgeIpxConnections( WorkContext->Endpoint );
  1809. //
  1810. // Load the SID from the connection into the request. Since this
  1811. // is a Negotiate request, we need to return a SID to the client.
  1812. // The easiest way to ensure that happens is to save the SID here.
  1813. //
  1814. SmbPutAlignedUshort( &header->Sid, WorkContext->Connection->Sid );
  1815. //
  1816. // Call the normal SMB processing routine.
  1817. //
  1818. SrvRestartReceive( WorkContext );
  1819. return;
  1820. } // IpxRestartReceive
  1821. NTSTATUS
  1822. RequeueIpxWorkItemAtSendCompletion (
  1823. IN PDEVICE_OBJECT DeviceObject,
  1824. IN PIRP Irp,
  1825. IN OUT PWORK_CONTEXT WorkContext
  1826. )
  1827. /*++
  1828. Routine Description:
  1829. This routine requeues an IPX work item to the free queue.
  1830. Arguments:
  1831. DeviceObject - Pointer to target device object for the request.
  1832. Irp - Pointer to I/O request packet
  1833. WorkContext - Caller-specified context parameter associated with IRP.
  1834. This is actually a pointer to a Work Context block.
  1835. Return Value:
  1836. STATUS_MORE_PROCESSING_REQUIRED.
  1837. --*/
  1838. {
  1839. //
  1840. // Check the status of the send completion.
  1841. //
  1842. CHECK_SEND_COMPLETION_STATUS_CONNECTIONLESS( Irp->IoStatus.Status );
  1843. //
  1844. // Reset the IRP cancelled bit.
  1845. //
  1846. Irp->Cancel = FALSE;
  1847. ASSERT( WorkContext->BlockHeader.ReferenceCount == 1 );
  1848. WorkContext->BlockHeader.ReferenceCount = 0;
  1849. ASSERT( WorkContext->Share == NULL );
  1850. ASSERT( WorkContext->Session == NULL );
  1851. ASSERT( WorkContext->TreeConnect == NULL );
  1852. ASSERT( WorkContext->Rfcb == NULL );
  1853. //
  1854. // Set up the restart routine in the work context.
  1855. //
  1856. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1857. WorkContext->FspRestartRoutine = SrvRestartReceive;
  1858. //
  1859. // Make sure the length specified in the MDL is correct -- it may
  1860. // have changed while sending a response to the previous request.
  1861. // Call an I/O subsystem routine to build the I/O request packet.
  1862. //
  1863. WorkContext->RequestBuffer->Mdl->ByteCount =
  1864. WorkContext->RequestBuffer->BufferLength;
  1865. //
  1866. // Requeue the work item.
  1867. //
  1868. RETURN_FREE_WORKITEM( WorkContext );
  1869. return STATUS_MORE_PROCESSING_REQUIRED;
  1870. } // RequeueIpxWorkItemAtSendCompletion
  1871. PCONNECTION
  1872. GetIpxConnection (
  1873. IN PWORK_CONTEXT WorkContext,
  1874. IN PENDPOINT Endpoint,
  1875. IN PTDI_ADDRESS_IPX ClientAddress,
  1876. IN PUCHAR ClientName
  1877. )
  1878. {
  1879. PLIST_ENTRY listEntry;
  1880. PCONNECTION connection;
  1881. PCHAR clientMachineName;
  1882. ULONG length;
  1883. KIRQL oldIrql;
  1884. PWORK_QUEUE queue = PROCESSOR_TO_QUEUE();
  1885. //
  1886. // Take a connection off the endpoint's free connection list.
  1887. //
  1888. // *** Note that all of the modifications done to the connection
  1889. // block are done with the spin lock held. This ensures that
  1890. // closing of the endpoint's connections will work properly if
  1891. // it happens simultaneously.
  1892. //
  1893. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  1894. listEntry = RemoveHeadList( &Endpoint->FreeConnectionList );
  1895. if ( listEntry == &Endpoint->FreeConnectionList ) {
  1896. //
  1897. // Unable to get a free connection.
  1898. //
  1899. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  1900. IF_DEBUG(IPX) KdPrint(( "SRVIPX: no free connections\n" ));
  1901. SrvOutOfFreeConnectionCount++;
  1902. return NULL;
  1903. }
  1904. //
  1905. // We have a connection and a table entry.
  1906. //
  1907. Endpoint->FreeConnectionCount--;
  1908. //
  1909. // Wake up the resource thread to create a new free connection
  1910. // for the endpoint.
  1911. //
  1912. if ( (Endpoint->FreeConnectionCount < SrvFreeConnectionMinimum) &&
  1913. (GET_BLOCK_STATE(Endpoint) == BlockStateActive) ) {
  1914. SrvResourceFreeConnection = TRUE;
  1915. SrvFsdQueueExWorkItem(
  1916. &SrvResourceThreadWorkItem,
  1917. &SrvResourceThreadRunning,
  1918. CriticalWorkQueue
  1919. );
  1920. }
  1921. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  1922. //
  1923. // Reference the connection to account for its being "open" and
  1924. // for the work item's pointer.
  1925. //
  1926. connection = CONTAINING_RECORD(
  1927. listEntry,
  1928. CONNECTION,
  1929. EndpointFreeListEntry
  1930. );
  1931. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  1932. SrvReferenceConnectionLocked( connection );
  1933. SrvReferenceConnectionLocked( connection );
  1934. //
  1935. // Mark the connection active.
  1936. //
  1937. SET_BLOCK_STATE( connection, BlockStateActive );
  1938. //
  1939. // Initialize IPX protocol fields.
  1940. //
  1941. connection->DirectHostIpx = TRUE;
  1942. connection->IpxAddress = *ClientAddress;
  1943. connection->SequenceNumber = 0;
  1944. connection->LastResponseLength = (USHORT)-1;
  1945. //
  1946. // Set the processor affinity
  1947. //
  1948. connection->PreferredWorkQueue = queue;
  1949. connection->CurrentWorkQueue = queue;
  1950. InterlockedIncrement( &queue->CurrentClients );
  1951. //
  1952. // Set the duplicate drop count. Start off conservative until
  1953. // we learn what kind of client we're dealing with
  1954. //
  1955. connection->IpxDropDuplicateCount = MIN_IPXDROPDUP;
  1956. connection->IpxDuplicateCount = 0;
  1957. #if MULTIPROCESSOR
  1958. //
  1959. // Get this client onto the best possible processor
  1960. //
  1961. SrvBalanceLoad( connection );
  1962. #endif
  1963. //
  1964. // Set time stamps. StartupTime is used by the server to determine
  1965. // whether the connection is old enough to be considered stale and
  1966. // should be closed when another negotiate comes in. This is used
  1967. // to fix a timing problem where identical negotiates may be
  1968. // queued up the the worker thread and a session setup comes in which
  1969. // gets partially processed in the indication routine.
  1970. //
  1971. SET_SERVER_TIME( connection->CurrentWorkQueue );
  1972. GET_SERVER_TIME( connection->CurrentWorkQueue, &connection->StartupTime );
  1973. connection->LastRequestTime = connection->StartupTime;
  1974. //
  1975. // Put the work item on the in-progress list.
  1976. //
  1977. SrvInsertTailList(
  1978. &connection->InProgressWorkItemList,
  1979. &WorkContext->InProgressListEntry
  1980. );
  1981. connection->InProgressWorkContextCount++;
  1982. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1983. WorkContext->Connection = connection;
  1984. //
  1985. // Copy the oem name at this time. We convert it to Unicode
  1986. // when we get the Session Setup SMB.
  1987. //
  1988. clientMachineName = connection->OemClientMachineName;
  1989. RtlCopyMemory( clientMachineName, ClientName, SMB_IPX_NAME_LENGTH );
  1990. clientMachineName[SMB_IPX_NAME_LENGTH] = '\0';
  1991. //
  1992. // Determine the number of characters that aren't blanks. This
  1993. // is used by the session APIs to simplify their processing.
  1994. //
  1995. for ( length = SMB_IPX_NAME_LENGTH;
  1996. length > 0 &&
  1997. (clientMachineName[length-1] == ' ' ||
  1998. clientMachineName[length-1] == '\0');
  1999. length-- ) ;
  2000. connection->OemClientMachineNameString.Length = (USHORT)length;
  2001. IF_DEBUG(IPX) {
  2002. SrvPrint2( "IpxRestartReceive accepting connection from %z on connection %p\n",
  2003. (PCSTRING)&connection->OemClientMachineNameString, connection );
  2004. }
  2005. return connection;
  2006. } // GetIpxConnection
  2007. VOID
  2008. PurgeIpxConnections (
  2009. IN PENDPOINT Endpoint
  2010. )
  2011. {
  2012. USHORT i,j;
  2013. KIRQL oldIrql;
  2014. PTABLE_HEADER tableHeader;
  2015. PCONNECTION connection;
  2016. IF_DEBUG(IPX2) KdPrint(( "SRVIPX: PurgeIpxConnections entered\n" ));
  2017. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  2018. for ( j = 1; j < ENDPOINT_LOCK_COUNT; j++ ) {
  2019. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2020. }
  2021. tableHeader = &Endpoint->ConnectionTable;
  2022. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  2023. connection = (PCONNECTION)tableHeader->Table[i].Owner;
  2024. if ( (connection == NULL) ||
  2025. (connection->IpxAddress.Socket != 0) ||
  2026. (GET_BLOCK_STATE(connection) != BlockStateActive) ) {
  2027. IF_DEBUG(IPX2) {
  2028. if ( connection == NULL ) {
  2029. KdPrint(( " no connection at table index %x\n", i ));
  2030. } else if ( connection->IpxAddress.Socket != 0 ) {
  2031. KdPrint(( " connection %p has socket %x\n", connection, connection->IpxAddress.Socket ));
  2032. } else {
  2033. KdPrint(( " connection %p has state %x\n", connection, GET_BLOCK_STATE(connection) ));
  2034. }
  2035. }
  2036. continue;
  2037. }
  2038. SrvReferenceConnectionLocked(connection);
  2039. for ( j = ENDPOINT_LOCK_COUNT-1; j > 0; j-- ) {
  2040. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2041. }
  2042. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2043. IF_DEBUG(IPX) KdPrint(( "SRVIPX: purging connection %p\n", connection ));
  2044. connection->DisconnectReason = DisconnectStaleIPXConnection;
  2045. SrvCloseConnection( connection, FALSE );
  2046. SrvDereferenceConnection( connection );
  2047. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  2048. for ( j = 1; j < ENDPOINT_LOCK_COUNT; j++ ) {
  2049. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2050. }
  2051. tableHeader = &Endpoint->ConnectionTable;
  2052. }
  2053. for ( j = ENDPOINT_LOCK_COUNT-1; j > 0; j-- ) {
  2054. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(j) );
  2055. }
  2056. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2057. IF_DEBUG(IPX2) KdPrint(( "SRVIPX: PurgeIpxConnections done\n" ));
  2058. return;
  2059. } // PurgeIpxConnections
  2060. VOID SRVFASTCALL
  2061. IpxRestartNegotiate(
  2062. IN OUT PWORK_CONTEXT WorkContext
  2063. )
  2064. /*++
  2065. Routine Description:
  2066. This routine handles the case where the transport did not
  2067. indicate us all of the data in the negotiate smb.
  2068. Arguments:
  2069. WorkContext - Supplies a pointer to the work context block
  2070. describing server-specific context for the request.
  2071. The workcontext block:
  2072. - has a pointer to the endpoint
  2073. - has a ref count of 1
  2074. Return Value:
  2075. None.
  2076. --*/
  2077. {
  2078. PENDPOINT endpoint;
  2079. USHORT sid;
  2080. PCONNECTION connection;
  2081. ULONG length;
  2082. PUCHAR clientName;
  2083. PTABLE_HEADER tableHeader;
  2084. USHORT i;
  2085. KIRQL oldIrql;
  2086. BOOLEAN resend;
  2087. USHORT error;
  2088. PLIST_ENTRY listEntry;
  2089. PTA_IPX_ADDRESS sourceAddress;
  2090. PNT_SMB_HEADER header;
  2091. PSMB_PARAMS params;
  2092. ASSERT( WorkContext->Endpoint != NULL );
  2093. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Negotiate received\n" ));
  2094. //
  2095. // If this endpoint is no longer around, ignore this request.
  2096. // This check covers the possibility that the endpoint has been
  2097. // removed between the time this request was queued to a worker
  2098. // thread and a worker thread actually picked up the request.
  2099. //
  2100. ACQUIRE_LOCK( &SrvEndpointLock );
  2101. listEntry = SrvEndpointList.ListHead.Flink;
  2102. while ( listEntry != &SrvEndpointList.ListHead ) {
  2103. endpoint = CONTAINING_RECORD(
  2104. listEntry,
  2105. ENDPOINT,
  2106. GlobalEndpointListEntry
  2107. );
  2108. if( endpoint == WorkContext->Endpoint &&
  2109. GET_BLOCK_STATE( endpoint ) == BlockStateActive ) {
  2110. //
  2111. // We found the endpoint, and it's still active! Reference
  2112. // it so the endpoint will not disappear out from under us.
  2113. //
  2114. endpoint->BlockHeader.ReferenceCount++;
  2115. break;
  2116. }
  2117. listEntry = listEntry->Flink;
  2118. }
  2119. if( listEntry == &SrvEndpointList.ListHead ) {
  2120. //
  2121. // We ran the whole list and did not find the endpoint. It
  2122. // must have gone away. Ignore this WorkItem.
  2123. //
  2124. RELEASE_LOCK( &SrvEndpointLock );
  2125. IF_DEBUG( IPX ) KdPrint(( "SRVIPX: Endpoint gone. ignoring\n" ));
  2126. goto return_workitem;
  2127. }
  2128. RELEASE_LOCK( &SrvEndpointLock );
  2129. //
  2130. // The endpoint is still valid, and we have referenced it. The local var
  2131. // 'endpoint' points to it.
  2132. //
  2133. sourceAddress = &WorkContext->ClientAddress->IpxAddress;
  2134. header = (PNT_SMB_HEADER) WorkContext->RequestHeader;
  2135. sid = SmbGetUshort( &header->Sid ); // NOT Aligned
  2136. ASSERT( sid == 0 );
  2137. clientName = (PUCHAR)WorkContext->RequestParameters;
  2138. clientName += 2 * (*clientName) + 1;
  2139. clientName += (*clientName) + 2;
  2140. //
  2141. // Make sure he's really trying to connect to us, and the SMB is well formed
  2142. //
  2143. if ( clientName+16+SMB_IPX_NAME_LENGTH-1 > END_OF_REQUEST_SMB( WorkContext ) ||
  2144. !RtlEqualMemory(
  2145. endpoint->TransportAddress.Buffer,
  2146. clientName + 16,
  2147. SMB_IPX_NAME_LENGTH ) ) {
  2148. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Negotiate sent to wrong name!\n" ));
  2149. error = SMB_ERR_NOT_ME;
  2150. resend = FALSE;
  2151. goto respond;
  2152. }
  2153. //
  2154. // Acquire the endpoint locks
  2155. //
  2156. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  2157. for ( i = 1; i < ENDPOINT_LOCK_COUNT; i++ ) {
  2158. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2159. }
  2160. tableHeader = &endpoint->ConnectionTable;
  2161. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  2162. connection = (PCONNECTION)tableHeader->Table[i].Owner;
  2163. if ( connection == NULL ) {
  2164. continue;
  2165. }
  2166. //
  2167. // Make sure this connection references an endpoint having
  2168. // the same netbios address that the new client is coming in on
  2169. //
  2170. // This is to allow a single server to be registered as more than
  2171. // one name on the network.
  2172. //
  2173. if( connection->Endpoint->TransportAddress.Length !=
  2174. endpoint->TransportAddress.Length ||
  2175. !RtlEqualMemory( connection->Endpoint->TransportAddress.Buffer,
  2176. endpoint->TransportAddress.Buffer,
  2177. endpoint->TransportAddress.Length ) ) {
  2178. //
  2179. // This connection is for an endpoint having a different network
  2180. // name than we have. Ignore it.
  2181. //
  2182. continue;
  2183. }
  2184. //
  2185. // Check the IPX address of the sender against this
  2186. // connection.
  2187. //
  2188. if ( RtlEqualMemory(
  2189. &connection->IpxAddress,
  2190. &sourceAddress->Address[0].Address[0],
  2191. sizeof(TDI_ADDRESS_IPX) ) ) {
  2192. //
  2193. // The IPX addresses match. Check the machine name.
  2194. //
  2195. if ( !RtlEqualMemory(
  2196. connection->OemClientMachineName,
  2197. clientName,
  2198. SMB_IPX_NAME_LENGTH) ) {
  2199. //
  2200. // The connection is for a different machine name.
  2201. // Mark it as no longer valid. It will be killed
  2202. // when the Negotiate SMB is processed.
  2203. //
  2204. IF_DEBUG(IPX)KdPrint(("SRVIPX: Found stale connection %p\n", connection ));
  2205. connection->IpxAddress.Socket = 0;
  2206. break;
  2207. } else if ( connection->SequenceNumber != 0 ) {
  2208. ULONG timeNow;
  2209. SET_SERVER_TIME( connection->CurrentWorkQueue );
  2210. GET_SERVER_TIME( connection->CurrentWorkQueue, &timeNow );
  2211. //
  2212. // If the connection was initialized less than 5 seconds ago,
  2213. // then we must be processing a duplicate negotiate request.
  2214. //
  2215. timeNow -= connection->StartupTime;
  2216. if ( timeNow > SrvFiveSecondTickCount ) {
  2217. //
  2218. // The connection has been active for more than 5 seconds.
  2219. // Mark it as no longer valid. It will be killed when
  2220. // the Negotiate SMB is processed.
  2221. //
  2222. IF_DEBUG(IPX) KdPrint(( "SRVIPX: found stale connection %p\n", connection ));
  2223. connection->IpxAddress.Socket = 0;
  2224. break;
  2225. } else {
  2226. //
  2227. // Don't bother replying to avoid confusing the client.
  2228. //
  2229. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2230. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2231. }
  2232. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2233. SrvDereferenceEndpoint( endpoint );
  2234. goto return_workitem;
  2235. }
  2236. }
  2237. //
  2238. // The connection is still in the initializing state and
  2239. // the names match, so handle this as a lost response.
  2240. //
  2241. IF_DEBUG(IPX) KdPrint(( "SRVIPX: Found initializing connection %p\n", connection ));
  2242. SmbPutUshort( &header->Sid, connection->Sid ); // NOT Aligned
  2243. goto duplicate_request;
  2244. } else {
  2245. IF_DEBUG(IPX) {
  2246. KdPrint(( " skipping index %x: different address\n", i ));
  2247. }
  2248. }
  2249. }
  2250. //
  2251. // Release the endpoint locks
  2252. //
  2253. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2254. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2255. }
  2256. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2257. //
  2258. // Get a free connection. If successful, the workcontext block will
  2259. // reference the connection block.
  2260. //
  2261. connection = GetIpxConnection(
  2262. WorkContext,
  2263. endpoint,
  2264. &sourceAddress->Address[0].Address[0],
  2265. clientName
  2266. );
  2267. //
  2268. // Now that we've gotten a connection structure for this endpoint,
  2269. // we can drop the reference we obtained above.
  2270. //
  2271. SrvDereferenceEndpoint( endpoint );
  2272. if ( connection == NULL ) {
  2273. //
  2274. // Unable to get a free connection.
  2275. //
  2276. goto return_workitem;
  2277. }
  2278. //
  2279. // Modify the FSP restart routine so that we can clean up stale
  2280. // connections.
  2281. //
  2282. IpxRestartReceive(WorkContext);
  2283. return;
  2284. duplicate_request:
  2285. //
  2286. // This is a duplicate request. If it's still being processed,
  2287. // indicate that to the client.
  2288. //
  2289. if ( connection->LastResponseLength == (USHORT)-1 ) {
  2290. IF_DEBUG(IPX) KdPrint(( "SRVIPX: request in progress\n" ));
  2291. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2292. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2293. }
  2294. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2295. error = SMB_ERR_WORKING;
  2296. resend = FALSE;
  2297. goto respond;
  2298. }
  2299. //
  2300. // The request has already been completed. Resend the response.
  2301. //
  2302. IF_DEBUG(IPX) KdPrint(( "SRVIPX: resending response\n" ));
  2303. resend = TRUE;
  2304. respond:
  2305. params = (PSMB_PARAMS)(header + 1);
  2306. header->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  2307. //
  2308. // Format the parameters portion of the SMB, and set the status.
  2309. //
  2310. if ( !resend ) {
  2311. SmbPutUshort( &header->Status.DosError.Error, error );
  2312. header->Status.DosError.ErrorClass = SMB_ERR_CLASS_SERVER;
  2313. header->Status.DosError.Reserved = 0;
  2314. params->WordCount = 0;
  2315. SmbPutUshort( &params->ByteCount, 0 );
  2316. length = sizeof(NT_SMB_HEADER) + sizeof(SMB_PARAMS);
  2317. } else {
  2318. //
  2319. // Copy the saved response data into the response.
  2320. //
  2321. SmbPutUlong( &header->Status.NtStatus, connection->LastResponseStatus );
  2322. RtlCopyMemory(
  2323. (PVOID)params,
  2324. connection->LastResponse,
  2325. connection->LastResponseLength
  2326. );
  2327. length = sizeof(NT_SMB_HEADER) + connection->LastResponseLength;
  2328. for ( i = ENDPOINT_LOCK_COUNT-1; i > 0; i-- ) {
  2329. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  2330. }
  2331. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  2332. }
  2333. WorkContext->ResponseBuffer->DataLength = length;
  2334. WorkContext->ResponseBuffer->Mdl->ByteCount = length;
  2335. //
  2336. // Give up the reference we earlier obtained
  2337. //
  2338. SrvDereferenceEndpoint( endpoint );
  2339. //
  2340. // Send the packet.
  2341. //
  2342. DEBUG WorkContext->FsdRestartRoutine = NULL;
  2343. StartSendNoConnection( WorkContext, FALSE, TRUE );
  2344. return;
  2345. return_workitem:
  2346. //
  2347. // Dereference the work item manually.
  2348. //
  2349. ASSERT( WorkContext->BlockHeader.ReferenceCount == 1 );
  2350. WorkContext->BlockHeader.ReferenceCount = 0;
  2351. WorkContext->Endpoint = NULL;
  2352. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2353. WorkContext->FspRestartRoutine = SrvRestartReceive;
  2354. WorkContext->Irp->Cancel = FALSE;
  2355. WorkContext->ProcessingCount = 0;
  2356. RETURN_FREE_WORKITEM( WorkContext );
  2357. return;
  2358. } // IpxRestartNegotiate
  2359. VOID SRVFASTCALL
  2360. SrvIpxFastRestartRead (
  2361. IN OUT PWORK_CONTEXT WorkContext
  2362. )
  2363. /*++
  2364. Routine Description:
  2365. Implements core read over ipx.
  2366. Arguments:
  2367. WorkContext - Supplies a pointer to the work context block
  2368. describing server-specific context for the request.
  2369. Return Value:
  2370. None.
  2371. --*/
  2372. {
  2373. PREQ_READ request;
  2374. PRESP_READ response;
  2375. PRFCB rfcb;
  2376. PLFCB lfcb;
  2377. PCHAR readAddress;
  2378. CLONG readLength;
  2379. LARGE_INTEGER offset;
  2380. ULONG key;
  2381. PSMB_HEADER header;
  2382. PAGED_CODE( );
  2383. request = (PREQ_READ)WorkContext->RequestParameters;
  2384. response = (PRESP_READ)WorkContext->ResponseParameters;
  2385. //
  2386. // Store in the work context block the time at which processing
  2387. // of the request began. Use the time that the work item was
  2388. // queued to the FSP for this purpose.
  2389. //
  2390. WorkContext->StartTime = WorkContext->Timestamp;
  2391. //
  2392. // Update the server network error count.
  2393. //
  2394. SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE );
  2395. //
  2396. // We have received an SMB.
  2397. //
  2398. SMBTRACE_SRV2(
  2399. WorkContext->ResponseBuffer->Buffer,
  2400. WorkContext->ResponseBuffer->DataLength
  2401. );
  2402. rfcb = WorkContext->Rfcb;
  2403. //
  2404. // Form the lock key using the FID and the PID.
  2405. //
  2406. // *** The FID must be included in the key in order to account for
  2407. // the folding of multiple remote compatibility mode opens into
  2408. // a single local open.
  2409. //
  2410. key = rfcb->ShiftedFid |
  2411. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2412. lfcb = rfcb->Lfcb;
  2413. //
  2414. // See if the direct host IPX smart card can handle this read. If so,
  2415. // return immediately, and the card will call our restart routine at
  2416. // SrvIpxSmartCardReadComplete
  2417. //
  2418. if( rfcb->PagedRfcb->IpxSmartCardContext ) {
  2419. IF_DEBUG( SIPX ) {
  2420. KdPrint(( "SrvIpxFastRestartRead: calling SmartCard Read for context %p\n",
  2421. WorkContext ));
  2422. }
  2423. WorkContext->Parameters.SmartCardRead.MdlReadComplete = lfcb->MdlReadComplete;
  2424. WorkContext->Parameters.SmartCardRead.DeviceObject = lfcb->DeviceObject;
  2425. if( SrvIpxSmartCard.Read( WorkContext->RequestBuffer->Buffer,
  2426. rfcb->PagedRfcb->IpxSmartCardContext,
  2427. key,
  2428. WorkContext ) == TRUE ) {
  2429. IF_DEBUG( SIPX ) {
  2430. KdPrint(( " SrvIpxFastRestartRead: SmartCard Read returns TRUE\n" ));
  2431. }
  2432. return;
  2433. }
  2434. IF_DEBUG( SIPX ) {
  2435. KdPrint(( " SrvIpxFastRestartRead: SmartCard Read returns FALSE\n" ));
  2436. }
  2437. }
  2438. IF_SMB_DEBUG(READ_WRITE1) {
  2439. KdPrint(( "Read request; FID 0x%lx, count %ld, offset %ld\n",
  2440. rfcb->Fid, SmbGetUshort( &request->Count ),
  2441. SmbGetUlong( &request->Offset ) ));
  2442. }
  2443. //
  2444. // Initialize the error class and code fields in the header to
  2445. // indicate success.
  2446. //
  2447. header = WorkContext->ResponseHeader;
  2448. SmbPutUlong( &header->ErrorClass, STATUS_SUCCESS );
  2449. //
  2450. // Determine the maximum amount of data we can read. This is the
  2451. // minimum of the amount requested by the client and the amount of
  2452. // room left in the response buffer. (Note that even though we may
  2453. // use an MDL read, the read length is still limited to the size of
  2454. // an SMB buffer.)
  2455. //
  2456. readAddress = (PCHAR)response->Buffer;
  2457. readLength = (ULONG)MIN(
  2458. (CLONG)SmbGetUshort( &request->Count ),
  2459. WorkContext->ResponseBuffer->BufferLength -
  2460. (readAddress - (PCHAR)header)
  2461. );
  2462. //
  2463. // Get the file offset.
  2464. //
  2465. offset.QuadPart = SmbGetUlong( &request->Offset );
  2466. //
  2467. // Try the fast I/O path first. If that fails, fall through to the
  2468. // normal build-an-IRP path.
  2469. //
  2470. if ( lfcb->FastIoRead != NULL ) {
  2471. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  2472. try {
  2473. if ( lfcb->FastIoRead(
  2474. lfcb->FileObject,
  2475. &offset,
  2476. readLength,
  2477. TRUE,
  2478. key,
  2479. readAddress,
  2480. &WorkContext->Irp->IoStatus,
  2481. lfcb->DeviceObject
  2482. ) ) {
  2483. //
  2484. // The fast I/O path worked. Call the restart routine directly
  2485. // to do postprocessing (including sending the response).
  2486. //
  2487. SrvFsdRestartRead( WorkContext );
  2488. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvIpxFastRestartRead complete.\n" ));
  2489. return;
  2490. }
  2491. }
  2492. except( EXCEPTION_EXECUTE_HANDLER ) {
  2493. // Fall through to the slow path on an exception
  2494. NTSTATUS status = GetExceptionCode();
  2495. IF_DEBUG(ERRORS) {
  2496. KdPrint(("FastIoRead threw exception %x\n", status ));
  2497. }
  2498. }
  2499. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  2500. }
  2501. //
  2502. // The turbo path failed. Build the read request, reusing the
  2503. // receive IRP.
  2504. //
  2505. //
  2506. // Note that we never do MDL reads here. The reasoning behind
  2507. // this is that because the read is going into an SMB buffer, it
  2508. // can't be all that large (by default, no more than 4K bytes),
  2509. // so the difference in cost between copy and MDL is minimal; in
  2510. // fact, copy read is probably faster than MDL read.
  2511. //
  2512. // Build an MDL describing the read buffer. Note that if the
  2513. // file system can complete the read immediately, the MDL isn't
  2514. // really needed, but if the file system must send the request
  2515. // to its FSP, the MDL _is_ needed.
  2516. //
  2517. // *** Note the assumption that the response buffer already has
  2518. // a valid full MDL from which a partial MDL can be built.
  2519. //
  2520. IoBuildPartialMdl(
  2521. WorkContext->ResponseBuffer->Mdl,
  2522. WorkContext->ResponseBuffer->PartialMdl,
  2523. readAddress,
  2524. readLength
  2525. );
  2526. //
  2527. // Build the IRP.
  2528. //
  2529. SrvBuildReadOrWriteRequest(
  2530. WorkContext->Irp, // input IRP address
  2531. lfcb->FileObject, // target file object address
  2532. WorkContext, // context
  2533. IRP_MJ_READ, // major function code
  2534. 0, // minor function code
  2535. readAddress, // buffer address
  2536. readLength, // buffer length
  2537. WorkContext->ResponseBuffer->PartialMdl, // MDL address
  2538. offset, // byte offset
  2539. key // lock key
  2540. );
  2541. IF_SMB_DEBUG(READ_WRITE2) {
  2542. KdPrint(( "SrvIpxFastRestartRead: copy read from file 0x%p, offset %ld, length %ld, destination 0x%p\n",
  2543. lfcb->FileObject, offset.LowPart, readLength,
  2544. readAddress ));
  2545. }
  2546. //
  2547. // Load the restart routine address and pass the request to the file
  2548. // system.
  2549. //
  2550. WorkContext->FsdRestartRoutine = SrvFsdRestartRead;
  2551. DEBUG WorkContext->FspRestartRoutine = NULL;
  2552. WorkContext->Irp->Cancel = FALSE;
  2553. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2554. //
  2555. // The read has been started. Control will return to the restart
  2556. // routine when the read completes.
  2557. //
  2558. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvIpxFastRestartRead complete.\n" ));
  2559. return;
  2560. } // SrvIpxFastRestartRead
  2561. BOOLEAN
  2562. SetupIpxFastCoreRead (
  2563. IN OUT PWORK_CONTEXT WorkContext
  2564. )
  2565. /*++
  2566. Routine Description:
  2567. Prepares the workitem for the fast restart read by validating the
  2568. smb and verifying the fid.
  2569. Arguments:
  2570. WorkContext
  2571. Return Value:
  2572. TRUE, if rfcb referenced.
  2573. FALSE, otherwise.
  2574. --*/
  2575. {
  2576. PREQ_READ request;
  2577. PRESP_READ response;
  2578. NTSTATUS status;
  2579. BOOLEAN validSmb;
  2580. USHORT fid;
  2581. PRFCB rfcb;
  2582. UCHAR wordCount;
  2583. USHORT byteCount;
  2584. PSMB_USHORT byteCountPtr;
  2585. ULONG availableSpaceForSmb;
  2586. ULONG smbLength;
  2587. PSMB_HEADER header;
  2588. PSMB_PARAMS params;
  2589. PCONNECTION connection;
  2590. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  2591. request = (PREQ_READ)WorkContext->RequestParameters;
  2592. response = (PRESP_READ)WorkContext->ResponseParameters;
  2593. IF_SMB_DEBUG(READ_WRITE1) {
  2594. KdPrint(( "Read request; FID 0x%lx, count %ld, offset %ld\n",
  2595. SmbGetUshort( &request->Fid ), SmbGetUshort( &request->Count ),
  2596. SmbGetUlong( &request->Offset ) ));
  2597. }
  2598. //
  2599. // Validate this smb.
  2600. //
  2601. header = WorkContext->RequestHeader;
  2602. params = (PVOID)(header + 1);
  2603. smbLength = WorkContext->RequestBuffer->DataLength;
  2604. wordCount = *((PUCHAR)params);
  2605. byteCountPtr = (PSMB_USHORT)( (PCHAR)params +
  2606. sizeof(UCHAR) + (5 * sizeof(USHORT)) );
  2607. byteCount = SmbGetUshort( (PSMB_USHORT)( (PCHAR)params +
  2608. sizeof(UCHAR) + (5 * sizeof(USHORT))) );
  2609. availableSpaceForSmb = smbLength - sizeof(SMB_HEADER);
  2610. //
  2611. // Validate the Read smb.
  2612. //
  2613. validSmb = (SmbGetUlong((PULONG)header->Protocol) == SMB_HEADER_PROTOCOL)
  2614. &&
  2615. ((CHAR)wordCount == 5)
  2616. &&
  2617. ((PCHAR)byteCountPtr <= (PCHAR)header + smbLength -
  2618. sizeof(USHORT))
  2619. &&
  2620. ((5*sizeof(USHORT) + sizeof(UCHAR) + sizeof(USHORT) +
  2621. byteCount) <= availableSpaceForSmb);
  2622. if ( validSmb ) {
  2623. PTABLE_HEADER tableHeader;
  2624. USHORT index;
  2625. USHORT sequence;
  2626. //
  2627. // Verify the FID. If verified, the RFCB is referenced and
  2628. // its address is stored in the WorkContext block, and the RFCB
  2629. // address is returned.
  2630. //
  2631. fid = SmbGetUshort( &request->Fid );
  2632. //
  2633. // Initialize local variables: obtain the connection block address
  2634. // and crack the FID into its components.
  2635. //
  2636. connection = WorkContext->Connection;
  2637. //
  2638. // Acquire the spin lock that guards the connection's file table.
  2639. //
  2640. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  2641. //
  2642. // See if this is the cached rfcb
  2643. //
  2644. if ( connection->CachedFid == (ULONG)fid ) {
  2645. rfcb = connection->CachedRfcb;
  2646. } else {
  2647. //
  2648. // Verify that the FID is in range, is in use, and has the correct
  2649. // sequence number.
  2650. index = FID_INDEX( fid );
  2651. sequence = FID_SEQUENCE( fid );
  2652. tableHeader = &connection->FileTable;
  2653. if ( (index >= (USHORT)tableHeader->TableSize) ||
  2654. (tableHeader->Table[index].Owner == NULL) ||
  2655. (tableHeader->Table[index].SequenceNumber != sequence) ) {
  2656. goto error_exit_locked;
  2657. }
  2658. rfcb = tableHeader->Table[index].Owner;
  2659. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  2660. goto error_exit_locked;
  2661. }
  2662. //
  2663. // If the caller wants to fail when there is a write behind
  2664. // error and the error exists, fill in NtStatus and do not
  2665. // return the RFCB pointer.
  2666. //
  2667. //
  2668. // !!! For now, we ignore write behind errors. Need to
  2669. // figure out how to translate the saved NT status to a
  2670. // DOS status...
  2671. //
  2672. #if 0
  2673. if ( !NT_SUCCESS(rfcb->SavedError) ) {
  2674. goto error_exit_locked;
  2675. }
  2676. #endif
  2677. //
  2678. // Cache the fid.
  2679. //
  2680. connection->CachedRfcb = rfcb;
  2681. connection->CachedFid = (ULONG)fid;
  2682. //
  2683. // The FID is valid within the context of this connection. Verify
  2684. // that the owning tree connect's TID is correct.
  2685. //
  2686. // Do not verify the UID for clients that do not understand it.
  2687. //
  2688. if ( (rfcb->Tid != SmbGetAlignedUshort(&header->Tid)) ||
  2689. (rfcb->Uid != SmbGetAlignedUshort(&header->Uid)) ) {
  2690. goto error_exit_locked;
  2691. }
  2692. }
  2693. //
  2694. // The file is active and the TID is valid. Reference the
  2695. // RFCB. Release the spin lock (we don't need it anymore).
  2696. //
  2697. rfcb->BlockHeader.ReferenceCount++;
  2698. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  2699. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2700. //
  2701. // Save the RFCB address in the work context block and
  2702. // return the file address.
  2703. //
  2704. WorkContext->Rfcb = rfcb;
  2705. ASSERT( GET_BLOCK_TYPE( rfcb->Mfcb ) == BlockTypeMfcb );
  2706. //
  2707. // Mark the rfcb as active
  2708. //
  2709. rfcb->IsActive = TRUE;
  2710. //
  2711. // Verify that the client has read access to the file via the
  2712. // specified handle.
  2713. //
  2714. if ( rfcb->ReadAccessGranted ) {
  2715. return(TRUE);
  2716. } else {
  2717. CHECK_PAGING_IO_ACCESS(
  2718. WorkContext,
  2719. rfcb->GrantedAccess,
  2720. &status );
  2721. if ( NT_SUCCESS( status ) ) {
  2722. return(TRUE);
  2723. }
  2724. }
  2725. }
  2726. return(FALSE);
  2727. error_exit_locked:
  2728. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  2729. return(FALSE);
  2730. } // SetupIpxFastCoreRead
  2731. VOID
  2732. SrvFreeIpxConnectionInIndication(
  2733. IN PWORK_CONTEXT WorkContext
  2734. )
  2735. {
  2736. PCONNECTION connection = WorkContext->Connection;
  2737. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  2738. SrvRemoveEntryList(
  2739. &connection->InProgressWorkItemList,
  2740. &WorkContext->InProgressListEntry
  2741. );
  2742. connection->InProgressWorkContextCount--;
  2743. if ( --connection->BlockHeader.ReferenceCount == 0 ) {
  2744. connection->BlockHeader.ReferenceCount++;
  2745. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  2746. //
  2747. // Orphaned. Send to Boys Town.
  2748. //
  2749. DispatchToOrphanage( (PVOID)connection );
  2750. } else {
  2751. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  2752. }
  2753. WorkContext->Connection = NULL;
  2754. return;
  2755. } // SrvFreeIpxConnectionInIndication
  2756. VOID
  2757. SrvIpxSmartCardReadComplete(
  2758. IN PVOID Context,
  2759. IN PFILE_OBJECT FileObject,
  2760. IN PMDL Mdl OPTIONAL,
  2761. IN ULONG Length
  2762. )
  2763. /*++
  2764. Routine Description:
  2765. Completes the Read performed by an optional smart card that handles
  2766. direct host IPX clients.
  2767. Arguments:
  2768. Context - the WorkContext of the original request
  2769. FileObject - the file being read from
  2770. Mdl - the MDL chain obtained from the cache manager to satisfy the read
  2771. Length - the length of the read
  2772. Return Value:
  2773. None
  2774. --*/
  2775. {
  2776. PWORK_CONTEXT workContext = Context;
  2777. PRFCB rfcb = workContext->Rfcb;
  2778. UCHAR command = workContext->NextCommand;
  2779. LARGE_INTEGER position;
  2780. KIRQL oldIrql;
  2781. NTSTATUS status;
  2782. ASSERT( workContext != NULL );
  2783. ASSERT( FileObject != NULL );
  2784. ASSERT( command == SMB_COM_READ || command == SMB_COM_READ_MPX );
  2785. //
  2786. // Figure out the file position
  2787. //
  2788. if( command == SMB_COM_READ ) {
  2789. PREQ_READ readParms = (PREQ_READ)workContext->RequestParameters;
  2790. position.QuadPart = SmbGetUlong( &readParms->Offset ) + Length;
  2791. } else {
  2792. PREQ_READ_MPX readMpxParms = (PREQ_READ_MPX)workContext->RequestParameters;
  2793. position.QuadPart = SmbGetUlong( &readMpxParms->Offset ) + Length;
  2794. }
  2795. IF_DEBUG( SIPX ) {
  2796. KdPrint(( "SrvIpxSmartCardReadComplete: %s %p Length %u, New Position %u\n",
  2797. command==SMB_COM_READ ? "SMB_COM_READ" : "SMB_COM_READ_MPX",
  2798. Context, Length, position.LowPart ));
  2799. }
  2800. //
  2801. // Update the position info in the rfcb
  2802. //
  2803. rfcb->CurrentPosition = position.LowPart;
  2804. UPDATE_READ_STATS( workContext, Length );
  2805. UPDATE_STATISTICS( workContext, Length, command );
  2806. if( ARGUMENT_PRESENT( Mdl ) ) {
  2807. //
  2808. // Give the MDL chain back to the cache manager
  2809. //
  2810. if( workContext->Parameters.SmartCardRead.MdlReadComplete == NULL ||
  2811. workContext->Parameters.SmartCardRead.MdlReadComplete( FileObject,
  2812. Mdl,
  2813. workContext->Parameters.SmartCardRead.DeviceObject ) == FALSE ) {
  2814. //
  2815. // Fast path didn't work -- try the IRP way
  2816. //
  2817. position.QuadPart -= Length;
  2818. status = SrvIssueMdlCompleteRequest( workContext, NULL,
  2819. Mdl,
  2820. IRP_MJ_READ,
  2821. &position,
  2822. Length
  2823. );
  2824. if( !NT_SUCCESS( status ) ) {
  2825. //
  2826. // This is very bad, what else can we do?
  2827. //
  2828. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2829. }
  2830. }
  2831. }
  2832. //
  2833. // Finish the cleanup
  2834. //
  2835. if( command == SMB_COM_READ ) {
  2836. workContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  2837. SrvFsdRestartSmbAtSendCompletion( NULL, workContext->Irp, workContext );
  2838. } else {
  2839. SrvFsdRestartSmbComplete( workContext );
  2840. }
  2841. }