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

3125 lines
104 KiB

  1. /*++
  2. Copyright (c) 1987-1999 Microsoft Corporation
  3. Module Name:
  4. smbcxchng.c
  5. Abstract:
  6. This is the include file that implements the SMB_*_EXCHANGE creation, deletion and
  7. dispatch routines.
  8. Notes:
  9. The exchange engine supports two kinds of changes, timed and untimed exhanges.
  10. The timed exchanges are distinguished by the SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION.
  11. In addition all exchanges are finalized if the transport is not able to push out
  12. the data within a specific period of time. This enables us to throttle back
  13. traffic to a overloaded server. Currently this is a global constant for all exchanges
  14. and is set to 300 seconds.
  15. This time limit only comes into play only when a send complete operation is outstanding
  16. The exchanges are put on a timed exchange list ( one for each type of exchange)
  17. when it is initiated. When a network operation, i.e., tranceive/send/copydata is
  18. initiated the corresponding expiry time in the exchange is updated by invoking the
  19. routine SmbCeSetExpiryTime.
  20. The echo probes are initiated is invoked through the context of a recurrent service
  21. (recursvc.c/recursvc.h). Every time this service is invoked (SmbCeProbeServers) it
  22. in turn invokes SmbCeDetectAndResumeExpiredExchanges. This routine detects those
  23. exchanges for which the wait for a response has exceeded the time limit and marks
  24. them for finalization.
  25. The finalization is done by SmbCeScavengeTimedOutExchanges in the context of a worker
  26. thread. Notice that due to the granularity mismatch we treat timeout intervals as
  27. soft deadlines.
  28. --*/
  29. #include "precomp.h"
  30. #pragma hdrstop
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text(PAGE, MRxSmbInitializeSmbCe)
  33. #pragma alloc_text(PAGE, SmbCeInitiateExchange)
  34. #pragma alloc_text(PAGE, SmbCeInitiateAssociatedExchange)
  35. #pragma alloc_text(PAGE, SmbCeExchangeAbort)
  36. #pragma alloc_text(PAGE, SmbCeBuildSmbHeader)
  37. #pragma alloc_text(PAGE, SmbCeResumeExchange)
  38. #pragma alloc_text(PAGE, SmbCepInitializeExchange)
  39. #pragma alloc_text(PAGE, SmbCeInitializeAssociatedExchange)
  40. #pragma alloc_text(PAGE, SmbCeTransformExchange)
  41. #pragma alloc_text(PAGE, SmbCePrepareExchangeForReuse)
  42. #pragma alloc_text(PAGE, SmbCeDiscardExchange)
  43. #pragma alloc_text(PAGE, SmbCeFinalizeExchangeWorkerThreadRoutine)
  44. #pragma alloc_text(PAGE, SmbCeFinalizeExchangeOnDisconnect)
  45. #pragma alloc_text(PAGE, SmbCeDetectExpiredExchanges)
  46. #pragma alloc_text(PAGE, DefaultSmbExchangeIndError)
  47. #pragma alloc_text(PAGE, DefaultSmbExchangeIndReceive)
  48. #pragma alloc_text(PAGE, DefaultSmbExchangeIndSendCallback)
  49. #endif
  50. ULONG SmbCeTraceExchangeReferenceCount = 0;
  51. RXDT_DefineCategory(SMBXCHNG);
  52. #define Dbg (DEBUG_TRACE_SMBXCHNG)
  53. // The exchange engine in the mini redirector requires to maintain enough state
  54. // to ensure that all the active exchanges are completed correctly when a shut down
  55. // occurs. Since the exchanges can be finalized by different threads, including
  56. // posted completions the exchange engine on startup initializes an event upon startup
  57. // which is subsequently used to signal the terminating condition.
  58. //
  59. // The count of active changes has to be tracked continously and the signalling
  60. // of the event depends upon the number of active exchanges reaching the count of
  61. // zero and the exchange engine being in a stopped state.
  62. SMBCE_STARTSTOP_CONTEXT SmbCeStartStopContext;
  63. NTSTATUS
  64. MRxSmbInitializeSmbCe()
  65. /*++
  66. Routine Description:
  67. This routine initializes the connection engine
  68. Return Value:
  69. NXSTATUS - The return status for the operation
  70. Notes:
  71. --*/
  72. {
  73. LONG i;
  74. PAGED_CODE();
  75. KeInitializeEvent(
  76. &SmbCeStartStopContext.StopEvent,
  77. NotificationEvent,
  78. FALSE);
  79. SmbCeStartStopContext.ActiveExchanges = 0;
  80. SmbCeStartStopContext.State = SMBCE_STARTED;
  81. SmbCeStartStopContext.pServerEntryTearDownEvent = NULL;
  82. InitializeListHead(
  83. &SmbCeStartStopContext.SessionSetupRequests);
  84. return STATUS_SUCCESS;
  85. }
  86. NTSTATUS
  87. MRxSmbTearDownSmbCe()
  88. /*++
  89. Routine Description:
  90. This routine tears down the connection engine
  91. Return Value:
  92. NXSTATUS - The return status for the operation
  93. Notes:
  94. --*/
  95. {
  96. BOOLEAN fWait;
  97. if (SmbCeStartStopContext.State == SMBCE_STARTED) {
  98. SmbCeAcquireSpinLock();
  99. SmbCeStartStopContext.State = SMBCE_STOPPED;
  100. fWait = (SmbCeStartStopContext.ActiveExchanges > 0);
  101. SmbCeReleaseSpinLock();
  102. if (fWait) {
  103. KeWaitForSingleObject(
  104. &SmbCeStartStopContext.StopEvent,
  105. Executive,
  106. KernelMode,
  107. FALSE,
  108. NULL);
  109. }
  110. }
  111. return STATUS_SUCCESS;
  112. }
  113. NTSTATUS
  114. SmbCeIncrementActiveExchangeCount()
  115. /*++
  116. Routine Description:
  117. This routine increments the active exchange count
  118. Return Value:
  119. NXSTATUS - The return status for the operation
  120. Notes:
  121. --*/
  122. {
  123. NTSTATUS Status = STATUS_SUCCESS;
  124. SmbCeAcquireSpinLock();
  125. if (SmbCeStartStopContext.State != SMBCE_STARTED) {
  126. Status = STATUS_UNSUCCESSFUL;
  127. } else {
  128. InterlockedIncrement(&SmbCeStartStopContext.ActiveExchanges);
  129. }
  130. SmbCeReleaseSpinLock();
  131. return Status;
  132. }
  133. VOID
  134. SmbCeDecrementActiveExchangeCount()
  135. /*++
  136. Routine Description:
  137. This routine decrements the active exchange count
  138. Return Value:
  139. NXSTATUS - The return status for the operation
  140. Notes:
  141. --*/
  142. {
  143. LONG FinalRefCount;
  144. ASSERT(SmbCeStartStopContext.ActiveExchanges > 0);
  145. if (InterlockedDecrement(&SmbCeStartStopContext.ActiveExchanges) == 0) {
  146. SmbCeAcquireSpinLock();
  147. if (SmbCeStartStopContext.State == SMBCE_STOPPED) {
  148. KeSetEvent(&SmbCeStartStopContext.StopEvent,0,FALSE);
  149. }
  150. SmbCeReleaseSpinLock();
  151. }
  152. }
  153. NTSTATUS
  154. SmbCeReferenceServer(
  155. PSMB_EXCHANGE pExchange)
  156. /*++
  157. Routine Description:
  158. This routine initializes the server associated with an exchange.
  159. Arguments:
  160. pExchange - the exchange to be initialized.
  161. Return Value:
  162. RXSTATUS - The return status for the operation
  163. Notes:
  164. The initiation of an exchange proceeds in multiple steps. The first step involves
  165. referencing the corresponding server,session and netroot entries. Subsequently the
  166. exchange is placed in a SMB_EXCHANGE_START state and the exchange is dispatched to the
  167. Start method. The act of referencing the session or the net root may suspend the exchange.
  168. The session and net roots are aliased entities, i.e., there is more then one reference
  169. to it. It is conceivable that the construction is in progress when a reference is made.
  170. In such cases the exchange is suspended and resumed when the construction is complete.
  171. On some transports a reconnect is possible without having to tear down an existing
  172. connection, i.e. attempting to send a packet reestablishes the connection at the
  173. lower level. Since this is not supported by all the transports ( with the exception
  174. of TCP/IP) the reference server entry initiates this process by tearing down the
  175. existing transport and reinitialising it.
  176. --*/
  177. {
  178. NTSTATUS Status = STATUS_SUCCESS;
  179. PSMBCEDB_SERVER_ENTRY pServerEntry;
  180. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  181. ASSERT(SmbCeIsResourceOwned());
  182. ASSERT(pExchange->SmbCeState == SMBCE_EXCHANGE_INITIALIZATION_START);
  183. if (pServerEntry->Header.State != SMBCEDB_ACTIVE) {
  184. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) {
  185. switch (pServerEntry->Header.State) {
  186. case SMBCEDB_INVALID:
  187. {
  188. SMBCEDB_OBJECT_STATE State;
  189. ASSERT(!pServerEntry->NegotiateInProgress);
  190. pServerEntry->NegotiateInProgress = TRUE;
  191. SmbCeUpdateServerEntryState(
  192. pServerEntry,
  193. SMBCEDB_CONSTRUCTION_IN_PROGRESS);
  194. SmbCeReleaseResource();
  195. // Initialize the transport associated with the server
  196. Status = SmbCeInitializeServerTransport(pServerEntry,NULL,NULL);
  197. if (Status == STATUS_SUCCESS) {
  198. PSMBCEDB_SESSION_ENTRY pSessionEntry =
  199. SmbCeGetExchangeSessionEntry(pExchange);
  200. Status = SmbCeNegotiate(
  201. pServerEntry,
  202. pServerEntry->pRdbssSrvCall
  203. );
  204. }
  205. SmbCeCompleteServerEntryInitialization(pServerEntry,Status);
  206. if (Status != STATUS_SUCCESS) {
  207. // Either the transport initialization failed or the NEGOTIATE
  208. // SMB could not be sent ....
  209. InterlockedIncrement(&MRxSmbStatistics.Reconnects);
  210. }
  211. SmbCeAcquireResource();
  212. }
  213. break;
  214. case SMBCEDB_CONSTRUCTION_IN_PROGRESS :
  215. {
  216. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  217. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)
  218. SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  219. if (pRequestEntry != NULL) {
  220. // Enqueue the request entry.
  221. pRequestEntry->ReconnectRequest.Type = RECONNECT_REQUEST;
  222. pRequestEntry->ReconnectRequest.pExchange = pExchange;
  223. SmbCeIncrementPendingLocalOperations(pExchange);
  224. SmbCeAddRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  225. Status = STATUS_PENDING;
  226. } else {
  227. Status = STATUS_INSUFFICIENT_RESOURCES;
  228. }
  229. }
  230. break;
  231. default :
  232. Status = STATUS_CONNECTION_DISCONNECTED;
  233. break;
  234. }
  235. } else {
  236. Status = STATUS_CONNECTION_DISCONNECTED;
  237. }
  238. }
  239. if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
  240. pExchange->SmbCeState = SMBCE_EXCHANGE_SERVER_INITIALIZED;
  241. }
  242. ASSERT(SmbCeIsResourceOwned());
  243. return Status;
  244. }
  245. NTSTATUS
  246. SmbCeReferenceSession(
  247. PSMB_EXCHANGE pExchange)
  248. /*++
  249. Routine Description:
  250. This routine initializes the session associated with an exchange.
  251. Arguments:
  252. pExchange - the exchange to be initialized.
  253. Return Value:
  254. RXSTATUS - The return status for the operation
  255. Notes:
  256. The initiation of an exchange proceeds in multiple steps. The first step involves
  257. referencing the corresponding server,session and netroot entries. Subsequently the
  258. exchange is placed in a SMB_EXCHANGE_START state and the exchange is dispatched to the
  259. Start method. The act of referencing the session or the net root may suspend the exchange.
  260. The session and net roots are aliased entities, i.e., there is more then one reference
  261. to it. It is conceivable that the construction is in progress when a reference is made.
  262. In such cases the exchange is suspended and resumed when the construction is complete.
  263. --*/
  264. {
  265. NTSTATUS Status;
  266. BOOLEAN fReestablishSession;
  267. BOOLEAN UnInitializeSecurityContext = FALSE;
  268. PSMBCEDB_SERVER_ENTRY pServerEntry;
  269. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  270. fReestablishSession = BooleanFlagOn(
  271. pExchange->SmbCeFlags,
  272. SMBCE_EXCHANGE_ATTEMPT_RECONNECTS);
  273. for (;;) {
  274. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  275. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  276. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  277. ASSERT(pExchange->SmbCeState == SMBCE_EXCHANGE_SERVER_INITIALIZED);
  278. ASSERT(SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER);
  279. ASSERT(SmbCeIsResourceOwned());
  280. Status = STATUS_USER_SESSION_DELETED;
  281. if (pSessionEntry == NULL) {
  282. break;
  283. }
  284. switch (pSessionEntry->Header.State) {
  285. case SMBCEDB_ACTIVE:
  286. Status = STATUS_SUCCESS;
  287. break;
  288. case SMBCEDB_INVALID:
  289. if (!fReestablishSession) {
  290. break;
  291. }
  292. RxDbgTrace( 0, Dbg, ("SmbCeReferenceSession: Reestablishing session\n"));
  293. // fall thru ...
  294. case SMBCEDB_START_CONSTRUCTION:
  295. {
  296. RxDbgTrace( 0, Dbg, ("SmbCeReferenceSession: Reestablishing session\n"));
  297. pSessionEntry->Session.UserId = 0;
  298. ASSERT(SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER);
  299. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
  300. pSessionEntry->pExchange = pExchange;
  301. pSessionEntry->Header.State = SMBCEDB_CONSTRUCTION_IN_PROGRESS;
  302. Status = STATUS_SUCCESS;
  303. }
  304. break;
  305. case SMBCEDB_CONSTRUCTION_IN_PROGRESS:
  306. if (fReestablishSession) {
  307. // The construction of the session is already in progress ....
  308. // Queue up the request to resume this exchange when the session
  309. // construction is complete.
  310. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  311. ASSERT(SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER);
  312. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)
  313. SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  314. if (pRequestEntry != NULL) {
  315. pRequestEntry->Request.pExchange = pExchange;
  316. SmbCeIncrementPendingLocalOperations(pExchange);
  317. SmbCeAddRequestEntry(&pSessionEntry->Requests,pRequestEntry);
  318. Status = STATUS_PENDING;
  319. } else {
  320. Status = STATUS_INSUFFICIENT_RESOURCES;
  321. }
  322. fReestablishSession = FALSE;
  323. }
  324. break;
  325. case SMBCEDB_MARKED_FOR_DELETION:
  326. Status = STATUS_USER_SESSION_DELETED;
  327. break;
  328. default:
  329. ASSERT(!"Valid Session State, SmbCe database corrupt");
  330. Status = STATUS_USER_SESSION_DELETED;
  331. }
  332. {
  333. if (UnInitializeSecurityContext) {
  334. SmbCeReleaseResource();
  335. UninitializeSecurityContextsForSession(&pSessionEntry->Session);
  336. SmbCeAcquireResource();
  337. }
  338. break;
  339. }
  340. }
  341. if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
  342. pExchange->SmbCeState = SMBCE_EXCHANGE_SESSION_INITIALIZED;
  343. }
  344. ASSERT(SmbCeIsResourceOwned());
  345. return Status;
  346. }
  347. NTSTATUS
  348. SmbCeReferenceNetRoot(
  349. PSMB_EXCHANGE pExchange)
  350. /*++
  351. Routine Description:
  352. This routine initializes the net root associated with an exchange.
  353. Arguments:
  354. pExchange - the exchange to be initialized.
  355. Return Value:
  356. RXSTATUS - The return status for the operation
  357. Notes:
  358. The initiation of an exchange proceeds in multiple steps. The first step involves
  359. referencing the corresponding server,session and netroot entries. Subsequently the
  360. exchange is placed in a SMB_EXCHANGE_START state and the exchange is dispatched to the
  361. Start method. The act of referencing the session or the net root may suspend the exchange.
  362. The session and net roots are aliased entities, i.e., there is more then one reference
  363. to it. It is conceivable that the construction is in progress when a reference is made.
  364. In such cases the exchange is suspended and resumed when the construction is complete.
  365. --*/
  366. {
  367. NTSTATUS Status;
  368. BOOLEAN fReconnectNetRoot;
  369. PSMBCEDB_SERVER_ENTRY pServerEntry;
  370. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  371. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  372. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pExchange->SmbCeContext.pVNetRoot);
  373. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  374. pNetRootEntry = SmbCeGetExchangeNetRootEntry(pExchange);
  375. ASSERT(pExchange->SmbCeState == SMBCE_EXCHANGE_SESSION_INITIALIZED);
  376. ASSERT(SmbCeIsResourceOwned());
  377. Status = STATUS_CONNECTION_DISCONNECTED;
  378. fReconnectNetRoot = BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_ATTEMPT_RECONNECTS);
  379. switch (pVNetRootContext->Header.State) {
  380. case SMBCEDB_ACTIVE:
  381. ASSERT(pNetRootEntry->Header.ObjectType == SMBCEDB_OT_NETROOT);
  382. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  383. Status = STATUS_SUCCESS;
  384. break;
  385. case SMBCEDB_INVALID:
  386. RxDbgTrace( 0, Dbg, ("SmbCeReferenceNetRoot: Reestablishing net root\n"));
  387. if (!fReconnectNetRoot) {
  388. break;
  389. }
  390. ClearFlag(
  391. pVNetRootContext->Flags,
  392. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  393. pVNetRootContext->TreeId = 0;
  394. // fall thru
  395. case SMBCEDB_START_CONSTRUCTION:
  396. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR;
  397. pVNetRootContext->pExchange = pExchange;
  398. pVNetRootContext->Header.State = SMBCEDB_CONSTRUCTION_IN_PROGRESS;
  399. Status = STATUS_SUCCESS;
  400. break;
  401. case SMBCEDB_CONSTRUCTION_IN_PROGRESS:
  402. if (fReconnectNetRoot) {
  403. // The construction of the net root is already in progress ....
  404. // Queue up the request to resume this exchange when the session
  405. // construction is complete.
  406. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  407. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)
  408. SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  409. if (pRequestEntry != NULL) {
  410. pRequestEntry->Request.pExchange = pExchange;
  411. SmbCeIncrementPendingLocalOperations(pExchange);
  412. SmbCeAddRequestEntry(&pVNetRootContext->Requests,pRequestEntry);
  413. Status = STATUS_PENDING;
  414. } else {
  415. Status = STATUS_INSUFFICIENT_RESOURCES;
  416. }
  417. }
  418. break;
  419. case SMBCEDB_MARKED_FOR_DELETION:
  420. break;
  421. default:
  422. ASSERT(!"Valid NetRoot State, SmbCe database corrupt");
  423. break;
  424. }
  425. if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
  426. pExchange->SmbCeState = SMBCE_EXCHANGE_NETROOT_INITIALIZED;
  427. }
  428. ASSERT(SmbCeIsResourceOwned());
  429. return Status;
  430. }
  431. NTSTATUS
  432. SmbCeInitiateExchange(
  433. PSMB_EXCHANGE pExchange)
  434. /*++
  435. Routine Description:
  436. This routine inititaes a exchange.
  437. Arguments:
  438. pExchange - the exchange to be initiated.
  439. Return Value:
  440. RXSTATUS - The return status for the operation
  441. Notes:
  442. The initiation of an exchange proceeds in multiple steps. The first step involves
  443. referencing the corresponding server,session and netroot entries. Subsequently the
  444. exchange is placed in a SMB_EXCHANGE_START state and the exchange is dispatched to the
  445. Start method. The act of referencing the session or the net root may suspend the exchange.
  446. --*/
  447. {
  448. NTSTATUS Status = STATUS_SUCCESS;
  449. PSMBCEDB_SERVER_ENTRY pServerEntry;
  450. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  451. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  452. PKEVENT pSmbCeSynchronizationEvent;
  453. PAGED_CODE();
  454. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  455. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  456. pNetRootEntry = SmbCeGetExchangeNetRootEntry(pExchange);
  457. ASSERT(pServerEntry != NULL);
  458. ASSERT(!FlagOn(pExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE));
  459. switch (SmbCeGetServerType(pServerEntry)) {
  460. case SMBCEDB_FILE_SERVER:
  461. // Admin exchanges do not have these fields filled in. All the three
  462. // entries must be valid for all other exchanges.
  463. if ((pExchange->NodeTypeCode != SMB_EXCHANGE_NTC(ADMIN_EXCHANGE)) &&
  464. ((pNetRootEntry == NULL) ||
  465. (pSessionEntry == NULL))) {
  466. Status = STATUS_REQUEST_ABORTED;
  467. break;
  468. }
  469. break;
  470. default:
  471. // Prepare for aborting the request if either the server type is invalid
  472. // or if the netroot entry or the session entry is invalid.
  473. Status = STATUS_REQUEST_ABORTED;
  474. }
  475. if (Status != STATUS_SUCCESS) {
  476. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: Exchange %lx Status %lx\n",pExchange,Status));
  477. return Status;
  478. }
  479. pSmbCeSynchronizationEvent = pExchange->pSmbCeSynchronizationEvent;
  480. if (pSmbCeSynchronizationEvent != NULL) {
  481. KeInitializeEvent(
  482. pSmbCeSynchronizationEvent,
  483. SynchronizationEvent,
  484. FALSE);
  485. }
  486. for (;;) {
  487. SmbCeAcquireResource();
  488. switch (pExchange->SmbCeState) {
  489. case SMBCE_EXCHANGE_INITIALIZATION_START:
  490. {
  491. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: Exchange %lx State %lx\n",pExchange,pExchange->SmbCeState));
  492. Status = SmbCeReferenceServer(pExchange);
  493. if (Status != STATUS_SUCCESS) {
  494. // this covers the case when the SERVER_ENTRY is under construction
  495. // and RxStatus(PENDING) is returned.
  496. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: SmbCeReferenceServer returned %lx\n",Status));
  497. break;
  498. }
  499. }
  500. // fall through
  501. case SMBCE_EXCHANGE_SERVER_INITIALIZED:
  502. if (Status == STATUS_SUCCESS) {
  503. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: Exchange %lx State %lx\n",pExchange,pExchange->SmbCeState));
  504. Status = SmbCeReferenceSession(pExchange);
  505. if (!NT_SUCCESS(Status)) {
  506. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: SmbCeReferenceSession returned %lx\n",Status));
  507. break;
  508. } if ((Status == STATUS_PENDING) &&
  509. !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR)) {
  510. break;
  511. }
  512. } else {
  513. break;
  514. }
  515. // fall through
  516. case SMBCE_EXCHANGE_SESSION_INITIALIZED:
  517. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: Exchange %lx State %lx\n",pExchange,pExchange->SmbCeState));
  518. Status = SmbCeReferenceNetRoot(pExchange);
  519. if (!NT_SUCCESS(Status)) {
  520. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: SmbCeReferenceNetRoot returned %lx\n",Status));
  521. break;
  522. } else if ((Status == STATUS_PENDING) &&
  523. !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR)) {
  524. break;
  525. }
  526. // else fall through
  527. case SMBCE_EXCHANGE_NETROOT_INITIALIZED:
  528. {
  529. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry2;
  530. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: Exchange %lx State %lx\n",pExchange,pExchange->SmbCeState));
  531. pNetRootEntry2 = SmbCeGetExchangeNetRootEntry(pExchange);
  532. if ((pNetRootEntry != NULL) &&
  533. !BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_INDEFINITE_DELAY_IN_RESPONSE)) {
  534. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION;
  535. }
  536. pExchange->SmbCeState = SMBCE_EXCHANGE_INITIATED;
  537. Status = STATUS_SUCCESS;
  538. }
  539. break;
  540. default:
  541. ASSERT(!"Valid State for a SMB exchange, exchange Initiation aborted");
  542. break;
  543. }
  544. SmbCeReleaseResource();
  545. if ((pSmbCeSynchronizationEvent != NULL) &&
  546. (pExchange->SmbCeState != SMBCE_EXCHANGE_INITIATED) &&
  547. (Status == STATUS_PENDING)) {
  548. KeWaitForSingleObject(
  549. pSmbCeSynchronizationEvent,
  550. Executive,
  551. KernelMode,
  552. FALSE,
  553. NULL );
  554. ASSERT(pExchange->Status != STATUS_PENDING);
  555. Status = pExchange->Status;
  556. if (Status != STATUS_SUCCESS) {
  557. break;
  558. }
  559. } else {
  560. break;
  561. }
  562. }
  563. ASSERT((Status != STATUS_PENDING) ||
  564. (pSmbCeSynchronizationEvent == NULL));
  565. RxDbgTrace(0,Dbg,("Exchange (%lx) Type (%lx) State(%lx) Status %lx \n",pExchange,pExchange->Type,pExchange->SmbCeState,Status));
  566. RxDbgTrace(0,Dbg,
  567. ("ServerEntry(%lx) SessionEntry(%lx) NetRootEntry(%lx) \n",
  568. pServerEntry,
  569. pSessionEntry,
  570. pNetRootEntry));
  571. // Note: Once the exchange has been initiated no further reference of the exchange
  572. // can be done since the state of the exchange is non-deterministic, i.e., depends upon
  573. // the scheduler.
  574. if (Status == STATUS_SUCCESS) {
  575. BOOLEAN ResourceReleased = FALSE;
  576. // Start the exchange
  577. ASSERT(pExchange->SmbCeState == SMBCE_EXCHANGE_INITIATED);
  578. SmbCeAcquireResource();
  579. if ((pServerEntry->Header.State == SMBCEDB_ACTIVE) ||
  580. (pExchange->NodeTypeCode == SMB_EXCHANGE_NTC(ADMIN_EXCHANGE))) {
  581. Status = SmbCeInitializeExchangeTransport(pExchange);
  582. } else {
  583. Status = STATUS_CONNECTION_DISCONNECTED;
  584. }
  585. if (Status == STATUS_SUCCESS) {
  586. if (pExchange->RxContext != NULL) {
  587. PMRXSMB_RX_CONTEXT pMRxSmbContext;
  588. // Set up the cancellation routine ..
  589. pMRxSmbContext = MRxSmbGetMinirdrContext(pExchange->RxContext);
  590. pMRxSmbContext->pCancelContext = pExchange;
  591. Status = RxSetMinirdrCancelRoutine(
  592. pExchange->RxContext,
  593. SmbCeCancelExchange);
  594. }
  595. if (Status == STATUS_SUCCESS) {
  596. if (!IsListEmpty(&pExchange->ExchangeList)) {
  597. RemoveEntryList(&pExchange->ExchangeList);
  598. }
  599. InsertTailList(
  600. &pServerEntry->ActiveExchanges,
  601. &pExchange->ExchangeList);
  602. SmbCeReleaseResource();
  603. ResourceReleased = TRUE;
  604. pExchange->SmbStatus = STATUS_SUCCESS;
  605. pExchange->ServerVersion = pServerEntry->Server.Version;
  606. Status = SMB_EXCHANGE_DISPATCH(pExchange,Start,((PSMB_EXCHANGE)pExchange));
  607. }
  608. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: SMB_EXCHANGE_DISPATCH(Start) returned %lx\n",Status));
  609. }
  610. if (!ResourceReleased) {
  611. SmbCeReleaseResource();
  612. }
  613. } else if (Status != STATUS_PENDING) {
  614. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: Exchange(%lx) Initiation failed %lx \n",pExchange,Status));
  615. }
  616. return Status;
  617. }
  618. NTSTATUS
  619. SmbCeInitiateAssociatedExchange(
  620. PSMB_EXCHANGE pExchange,
  621. BOOLEAN EnableCompletionHandlerInMasterExchange)
  622. /*++
  623. Routine Description:
  624. This routine inititaes an associated exchange.
  625. Arguments:
  626. pExchange - the exchange to be initiated.
  627. Return Value:
  628. NTSTATUS - The return status for the operation
  629. Notes:
  630. --*/
  631. {
  632. NTSTATUS Status = STATUS_SUCCESS;
  633. PSMB_EXCHANGE pMasterExchange;
  634. PSMBCEDB_SERVER_ENTRY pServerEntry;
  635. PAGED_CODE();
  636. ASSERT(pExchange->SmbCeState == SMBCE_EXCHANGE_INITIATED);
  637. ASSERT(FlagOn(pExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE));
  638. pMasterExchange = pExchange->Associated.pMasterExchange;
  639. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  640. ASSERT(pServerEntry != NULL);
  641. // Note: Once the exchange has been initiated no further reference of the exchange
  642. // can be done since the state of the exchange is non-deterministic, i.e., depends upon
  643. // the scheduler.
  644. Status = SmbCeInitializeExchangeTransport(pExchange);
  645. SmbCeAcquireResource();
  646. if (!IsListEmpty(&pExchange->ExchangeList)) {
  647. RemoveEntryList(&pExchange->ExchangeList);
  648. }
  649. InsertTailList(
  650. &pServerEntry->ActiveExchanges,
  651. &pExchange->ExchangeList);
  652. if (EnableCompletionHandlerInMasterExchange) {
  653. ASSERT(!FlagOn(
  654. pMasterExchange->SmbCeFlags,
  655. SMBCE_ASSOCIATED_EXCHANGES_COMPLETION_HANDLER_ACTIVATED));
  656. SetFlag(
  657. pMasterExchange->SmbCeFlags,
  658. SMBCE_ASSOCIATED_EXCHANGES_COMPLETION_HANDLER_ACTIVATED);
  659. }
  660. pExchange->SmbStatus = STATUS_SUCCESS;
  661. pExchange->ServerVersion = pServerEntry->Server.Version;
  662. SmbCeReleaseResource();
  663. if (Status == STATUS_SUCCESS) {
  664. Status = SMB_EXCHANGE_DISPATCH(pExchange,Start,((PSMB_EXCHANGE)pExchange));
  665. RxDbgTrace( 0, Dbg, ("SmbCeInitiateExchange: SMB_EXCHANGE_DISPATCH(Start) returned %lx\n",Status));
  666. } else {
  667. SmbCeFinalizeExchange(pExchange);
  668. Status = STATUS_PENDING;
  669. }
  670. return Status;
  671. }
  672. NTSTATUS
  673. SmbCeExchangeAbort(
  674. PSMB_EXCHANGE pExchange)
  675. /*++
  676. Routine Description:
  677. This routine aborts an exchange.
  678. Arguments:
  679. pExchange - the exchange to be aborted.
  680. Return Value:
  681. RXSTATUS - The return status for the operation
  682. Notes:
  683. --*/
  684. {
  685. PAGED_CODE();
  686. RxDbgTrace( 0, Dbg, ("SmbCeExchangeAbort: Exchange %lx aborted\n",pExchange));
  687. SmbCeDiscardExchange(pExchange);
  688. return STATUS_SUCCESS;
  689. }
  690. NTSTATUS
  691. SmbCeBuildSmbHeader(
  692. IN OUT PSMB_EXCHANGE pExchange,
  693. IN OUT PVOID pBuffer,
  694. IN ULONG BufferLength,
  695. OUT PULONG pBufferConsumed,
  696. OUT PUCHAR pLastCommandInHeader,
  697. OUT PUCHAR *pNextCommandPtr)
  698. /*++
  699. Routine Description:
  700. This routine constructs the SMB header associated with any SMB sent as part of
  701. an exchange.
  702. Arguments:
  703. pExchange - the exchange for which the SMB is to be constructed.
  704. pBuffer - the buffer in whihc the SMB header is to be constructed
  705. BufferLength - length of the buffer
  706. pBufferConsumed - the buffer consumed
  707. pLastCommandInHeader - the last command in header, SMB_COM_NO_ANDX_COMMAND if none
  708. pNextCommandPtr - the ptr to the place in the buffer where the next command
  709. code should be copied.
  710. Return Value:
  711. STATUS_SUCCESS - if the header construction was successful
  712. Notes:
  713. This routine is called to build the SMB header. This centralization allows us to
  714. compound the SMB operation with other SMB's required for the maintenance of the
  715. SMB connection engine data structures. It also provides us with a centralized facility
  716. for profiling SMB's as well as a one place mechanism for filling in all the header
  717. fields associated with a SMB.
  718. --*/
  719. {
  720. NTSTATUS Status = STATUS_SUCCESS;
  721. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pBuffer;
  722. PGENERIC_ANDX pSmbBuffer;
  723. ULONG SmbBufferUnconsumed = BufferLength;
  724. PUCHAR pSmbCommand;
  725. UCHAR LastCommandInHeader = SMB_COM_NO_ANDX_COMMAND;
  726. UCHAR Flags = SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS;
  727. USHORT Flags2 = 0;
  728. PSMBCEDB_SERVER_ENTRY pServerEntry;
  729. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  730. PSMBCE_SERVER pServer;
  731. PAGED_CODE();
  732. if (BufferLength < sizeof(SMB_HEADER)) {
  733. RxDbgTrace( 0, Dbg, ("SmbCeBuildSmbHeader: BufferLength too small %d\n",BufferLength));
  734. ASSERT(!"Buffer too small");
  735. return STATUS_BUFFER_TOO_SMALL;
  736. }
  737. SmbBufferUnconsumed = BufferLength - sizeof(SMB_HEADER);
  738. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  739. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  740. pServer = SmbCeGetExchangeServer(pExchange);
  741. if (pServer->Dialect == NTLANMAN_DIALECT) {
  742. if (FlagOn(pServer->DialectFlags,DF_NT_SMBS)) {
  743. Flags2 |= (SMB_FLAGS2_KNOWS_EAS );
  744. if (FlagOn(pServer->DialectFlags,DF_UNICODE)) {
  745. Flags2 |= SMB_FLAGS2_UNICODE;
  746. }
  747. }
  748. if (FlagOn(pServer->DialectFlags,DF_NT_STATUS)) {
  749. Flags2 |= SMB_FLAGS2_NT_STATUS;
  750. }
  751. }
  752. if (FlagOn(pServer->DialectFlags,DF_LONGNAME)) {
  753. Flags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
  754. }
  755. if (FlagOn(pServer->DialectFlags,DF_SUPPORTEA)) {
  756. Flags2 |= SMB_FLAGS2_KNOWS_EAS;
  757. }
  758. RtlZeroMemory(pSmbHeader,sizeof(SMB_HEADER));
  759. *((PULONG)&pSmbHeader->Protocol) = SMB_HEADER_PROTOCOL;
  760. pSmbHeader->Flags = Flags;
  761. pSmbHeader->Flags2 = Flags2;
  762. pSmbHeader->Pid = MRXSMB_PROCESS_ID;
  763. pSmbHeader->Uid = 0;
  764. pSmbHeader->Tid = 0;
  765. pSmbHeader->ErrorClass = 0;
  766. pSmbHeader->Reserved = 0;
  767. pSmbCommand = &pSmbHeader->Command;
  768. SmbPutUshort(&pSmbHeader->Error,0);
  769. switch (SmbCeGetServerType(pServerEntry)) {
  770. case SMBCEDB_FILE_SERVER:
  771. {
  772. BOOLEAN fValidTid;
  773. if (pSessionEntry != NULL) {
  774. pSmbHeader->Uid = pSessionEntry->Session.UserId;
  775. }
  776. if (pExchange->SmbCeContext.pVNetRoot != NULL) {
  777. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  778. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(
  779. pExchange->SmbCeContext.pVNetRoot);
  780. fValidTid = BooleanFlagOn(
  781. pVNetRootContext->Flags,
  782. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  783. pSmbHeader->Tid = pVNetRootContext->TreeId;
  784. } else {
  785. fValidTid = TRUE;
  786. }
  787. pSmbBuffer = (PGENERIC_ANDX)(pSmbHeader + 1);
  788. if ((pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) ||
  789. (pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR)) {
  790. // There is an oppurtunity to compound some SessionSetup/TreeConnect SMB with the
  791. // given SMB command.
  792. if ((pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) &&
  793. (pSessionEntry->Header.State == SMBCEDB_CONSTRUCTION_IN_PROGRESS)) {
  794. if (( pServer->DialectFlags & DF_EXTENDNEGOT) ||
  795. ( pServer->DialectFlags & DF_NTNEGOTIATE)) {
  796. RxDbgTrace( 0, Dbg, ("SmbCeBuildSmbHeader: Building Session setup And X\n"));
  797. *pSmbCommand = SMB_COM_SESSION_SETUP_ANDX;
  798. LastCommandInHeader = *pSmbCommand;
  799. pSmbCommand = &pSmbBuffer->AndXCommand;
  800. pSmbHeader->Tid = 0;
  801. Status = SMBCE_SERVER_DIALECT_DISPATCH(
  802. pServer,
  803. BuildSessionSetup,
  804. (pExchange,
  805. pSmbBuffer,
  806. &SmbBufferUnconsumed));
  807. if (NT_SUCCESS(Status)) {
  808. // Update the buffer for the construction of the following SMB.
  809. SmbPutUshort(
  810. &pSmbBuffer->AndXOffset,
  811. (USHORT)(BufferLength - SmbBufferUnconsumed));
  812. pSmbBuffer = (PGENERIC_ANDX)((PBYTE)pBuffer + BufferLength - SmbBufferUnconsumed);
  813. }
  814. }
  815. } else {
  816. NOTHING; //no sess for share level AT LEAST NOT FOR CORE!!!
  817. }
  818. if (NT_SUCCESS(Status) &&
  819. (pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR) &&
  820. !fValidTid) {
  821. BOOLEAN BuildingTreeConnectAndX = BooleanFlagOn(pServer->DialectFlags,DF_LANMAN10);
  822. if (BuildingTreeConnectAndX) {
  823. RxDbgTrace( 0, Dbg, ("SmbCeBuildSmbHeader: Building Tree Connect And X\n"));
  824. *pSmbCommand = SMB_COM_TREE_CONNECT_ANDX;
  825. LastCommandInHeader = *pSmbCommand;
  826. } else {
  827. RxDbgTrace( 0, Dbg, ("SmbCeBuildSmbHeader: Building Tree Connect No X\n"));
  828. *pSmbCommand = SMB_COM_TREE_CONNECT;
  829. LastCommandInHeader = *pSmbCommand;
  830. }
  831. Status = SMBCE_SERVER_DIALECT_DISPATCH(
  832. pServer,
  833. BuildTreeConnect,
  834. (pExchange,
  835. pSmbBuffer,
  836. &SmbBufferUnconsumed));
  837. if (NT_SUCCESS(Status)) {
  838. // Update the buffer for the construction of the following SMB.
  839. if (BuildingTreeConnectAndX) {
  840. pSmbCommand = &pSmbBuffer->AndXCommand;
  841. SmbPutUshort(&pSmbBuffer->AndXOffset,(USHORT)(BufferLength - SmbBufferUnconsumed));
  842. } else {
  843. pSmbCommand = NULL;
  844. }
  845. }
  846. }
  847. }
  848. }
  849. break;
  850. default:
  851. {
  852. ASSERT(!"Valid Server Type");
  853. Status = STATUS_INVALID_HANDLE;
  854. }
  855. break;
  856. }
  857. *pNextCommandPtr = pSmbCommand;
  858. *pBufferConsumed = BufferLength - SmbBufferUnconsumed;
  859. *pLastCommandInHeader = LastCommandInHeader;
  860. RxDbgTrace( 0, Dbg, ("SmbCeBuildSmbHeader: Buffer Consumed %lx\n",*pBufferConsumed));
  861. if (Status != STATUS_SUCCESS) {
  862. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) {
  863. pExchange->SessionSetupStatus = Status;
  864. }
  865. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR) {
  866. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  867. pVNetRootContext = SmbCeGetExchangeVNetRootContext(pExchange);
  868. SmbCeUpdateVNetRootContextState(
  869. pVNetRootContext,
  870. SMBCEDB_INVALID);
  871. }
  872. }
  873. return Status;
  874. }
  875. typedef struct __Service_Name_Entry {
  876. NET_ROOT_TYPE NetRootType;
  877. USHORT NameLength;
  878. PBYTE Name;
  879. };
  880. struct __Service_Name_Entry ServiceNameTable[] = {
  881. {NET_ROOT_DISK,sizeof(SHARE_TYPE_NAME_DISK),SHARE_TYPE_NAME_DISK},
  882. {NET_ROOT_PIPE,sizeof(SHARE_TYPE_NAME_PIPE),SHARE_TYPE_NAME_PIPE},
  883. {NET_ROOT_PRINT,sizeof(SHARE_TYPE_NAME_PRINT),SHARE_TYPE_NAME_PRINT},
  884. {NET_ROOT_COMM,sizeof(SHARE_TYPE_NAME_COMM),SHARE_TYPE_NAME_COMM} //COMM must be last
  885. };
  886. UNICODE_STRING FileSystem_NTFS_UNICODE = {8,8,L"NTFS"};
  887. UNICODE_STRING FileSystem_FAT_UNICODE = {6,6,L"FAT"};
  888. CHAR FileSystem_NTFS[] = "NTFS";
  889. CHAR FileSystem_FAT[] = "FAT";
  890. NTSTATUS
  891. SmbCeParseSmbHeader(
  892. PSMB_EXCHANGE pExchange,
  893. PSMB_HEADER pSmbHeader,
  894. PGENERIC_ANDX pCommandToProcess,
  895. NTSTATUS *pSmbResponseStatus,
  896. ULONG BytesAvailable,
  897. ULONG BytesIndicated,
  898. PULONG pBytesConsumed)
  899. /*++
  900. Routine Description:
  901. This routine validates the SMB header associated with any SMB received as part of
  902. an exchange.
  903. Arguments:
  904. pExchange - the exchange for which the SMB is to be constructed.
  905. pSmbHeader - the header of the SMB received
  906. pCommandToProcess - the SMB command to be processed after the header ( Can be NULL )
  907. pSmbResponseStatus - the status in the SMB response header (Can be NULL)
  908. BytesAvailable - the bytes available for processing but not necesarily indicated.
  909. BytesIndicated - the length of the SMB buffer avcailable for perusal
  910. pBytesConsumed - the buffer consumed
  911. Return Value:
  912. RXSTATUS - The return status for the operation
  913. STATUS_MORE_PROCESSING_REQUIRED -- if a copy of the data needs to be done before
  914. processing can be completed. This occurs because sufficient data was not
  915. indicated to process the header.
  916. STATUS_SUCCESS -- the header was processed succesfully. In such cases the GENERIC_ANDX
  917. if not NULL will contain the offset from the start of the buffer and the command
  918. to be processed.
  919. STATUS_* -- They indicate an error which would normally lead to the abortion of the
  920. exchange.
  921. Notes:
  922. This routine is called to parse the SMB header. This centralization allows us to
  923. implement a one stop mechanism for updateing/validating the header fields as well as
  924. resuming the exchanges waiting for the construction of session/net root entry
  925. associated with this exchange
  926. --*/
  927. {
  928. NTSTATUS Status = STATUS_SUCCESS;
  929. NTSTATUS SmbResponseStatus;
  930. PBYTE pSmbBuffer = (PBYTE)pSmbHeader;
  931. UCHAR SmbCommand;
  932. BOOLEAN fUpdateVNetRootContext = FALSE;
  933. SMBCEDB_OBJECT_STATE SessionState;
  934. SMBCEDB_OBJECT_STATE NetRootState;
  935. PMRX_V_NET_ROOT pVNetRoot;
  936. PSMBCEDB_SERVER_ENTRY pServerEntry;
  937. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  938. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  939. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  940. pVNetRoot = SmbCeGetExchangeVNetRoot(pExchange);
  941. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  942. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  943. pNetRootEntry = SmbCeGetExchangeNetRootEntry(pExchange);
  944. pVNetRootContext = SmbCeGetExchangeVNetRootContext(pExchange);
  945. // Return Immediately if bytes indicated is less then the size of a SMB header.
  946. if (BytesIndicated < sizeof(SMB_HEADER)) {
  947. *pBytesConsumed = BytesIndicated;
  948. return STATUS_INVALID_NETWORK_RESPONSE;
  949. }
  950. SmbResponseStatus = GetSmbResponseNtStatus(pSmbHeader,pExchange);
  951. if (!NT_SUCCESS(SmbResponseStatus)) {
  952. RxDbgTrace( 0, Dbg, ("SmbCeParseSmbHeader::SMB Response Error %lx\n",SmbResponseStatus));
  953. }
  954. SmbCommand = pSmbHeader->Command;
  955. *pBytesConsumed = sizeof(SMB_HEADER);
  956. pSmbBuffer += *pBytesConsumed;
  957. // There are certain SMB's that effect the connection engine data structures as
  958. // well as the exchange that has been suspended. These are the SMB's used for tree
  959. // connect and session setup.
  960. // In all the other cases no special action is required for the maintenance of the
  961. // connection engine data structures. The Exchange that was suspended needs to be
  962. // resumed.
  963. if (SmbCommand == SMB_COM_SESSION_SETUP_ANDX) {
  964. if (SmbResponseStatus != STATUS_SUCCESS) {
  965. if ((FIELD_OFFSET(GENERIC_ANDX,AndXReserved) + *pBytesConsumed) <= BytesIndicated) {
  966. PGENERIC_ANDX pGenericAndX = (PGENERIC_ANDX)pSmbBuffer;
  967. if (pGenericAndX->WordCount == 0) {
  968. Status = SmbResponseStatus;
  969. }
  970. pExchange->SessionSetupStatus = SmbResponseStatus;
  971. }
  972. // Note that the case wherein sufficient bytes are not indicated for the
  973. // GENERIC_ANDX response is handled by the if statement below which
  974. // imposes a more stringent test.
  975. }
  976. if ((Status == STATUS_SUCCESS) &&
  977. (FIELD_OFFSET(RESP_SESSION_SETUP_ANDX,Buffer) + *pBytesConsumed) > BytesIndicated) {
  978. Status = STATUS_MORE_PROCESSING_REQUIRED;
  979. }
  980. if (Status == STATUS_SUCCESS) {
  981. PRESP_SESSION_SETUP_ANDX pSessionSetupResponse;
  982. ULONG SessionSetupResponseLength,ByteCount;
  983. RxDbgTrace( 0, Dbg, ("Processing Session Setup ANd X\n"));
  984. pSessionSetupResponse = (PRESP_SESSION_SETUP_ANDX)(pSmbBuffer);
  985. ByteCount = SmbGetUshort(&pSessionSetupResponse->ByteCount);
  986. if (pSessionSetupResponse->WordCount == 3) {
  987. SmbCommand = pSessionSetupResponse->AndXCommand;
  988. if (SmbCommand == SMB_COM_NO_ANDX_COMMAND) {
  989. SessionSetupResponseLength =
  990. FIELD_OFFSET(RESP_SESSION_SETUP_ANDX,Buffer) + ByteCount;
  991. Status = SmbResponseStatus;
  992. } else {
  993. SessionSetupResponseLength =
  994. SmbGetUshort(&pSessionSetupResponse->AndXOffset) - *pBytesConsumed;
  995. }
  996. //if (ByteCount == 0) {
  997. // //bytecount==0 and NTDIALECT means that this is really w95...change the flags
  998. // PSMBCE_SERVER pServer = &pExchange->SmbCeContext.pServerEntry->Server;
  999. // if (FlagOn(pServer->DialectFlags,DF_NTPROTOCOL)) {
  1000. // pServer->DialectFlags &= ~(DF_MIXEDCASEPW);
  1001. // pServer->DialectFlags |= DF_W95;
  1002. // }
  1003. //}
  1004. } else {
  1005. Status = SmbResponseStatus;
  1006. }
  1007. if (NT_SUCCESS(Status)) {
  1008. if (SessionSetupResponseLength + *pBytesConsumed <= BytesIndicated) {
  1009. *pBytesConsumed += SessionSetupResponseLength;
  1010. pSmbBuffer += SessionSetupResponseLength;
  1011. pSessionEntry->Session.UserId = pSmbHeader->Uid;
  1012. if (FlagOn(SmbGetUshort(&pSessionSetupResponse->Action), SMB_SETUP_USE_LANMAN_KEY)) {
  1013. pSessionEntry->Session.Flags |=
  1014. SMBCE_SESSION_FLAGS_LANMAN_SESSION_KEY_USED;
  1015. }
  1016. if (FlagOn(SmbGetUshort(&pSessionSetupResponse->Action), SMB_SETUP_GUEST)) {
  1017. pSessionEntry->Session.Flags |=
  1018. SMBCE_SESSION_FLAGS_GUEST_SESSION;
  1019. }
  1020. pExchange->SessionSetupStatus = STATUS_SUCCESS;
  1021. InterlockedIncrement(&MRxSmbStatistics.Sessions);
  1022. } else {
  1023. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1024. }
  1025. } else {
  1026. RxDbgTrace( 0, Dbg, ("SmbCeParseSmbHeader::Session setup and X Response %lx\n",Status));
  1027. pExchange->SessionSetupStatus = Status;
  1028. InterlockedIncrement(&MRxSmbStatistics.FailedSessions);
  1029. if ((SmbCommand == SMB_COM_TREE_CONNECT_ANDX) ||
  1030. (SmbCommand == SMB_COM_TREE_CONNECT)) {
  1031. RxDbgTrace( 0, Dbg, ("SmbCeParseSmbHeader:: Tearing down a tree connection\n"));
  1032. fUpdateVNetRootContext = TRUE;
  1033. NetRootState = SMBCEDB_INVALID;
  1034. }
  1035. }
  1036. }
  1037. }
  1038. if ((SmbCommand == SMB_COM_TREE_CONNECT_ANDX) &&
  1039. NT_SUCCESS(Status)) {
  1040. if (SmbResponseStatus != STATUS_SUCCESS) {
  1041. if ((FIELD_OFFSET(GENERIC_ANDX,AndXReserved) + *pBytesConsumed) <= BytesIndicated) {
  1042. PGENERIC_ANDX pGenericAndX = (PGENERIC_ANDX)pSmbBuffer;
  1043. if (pGenericAndX->WordCount == 0) {
  1044. Status = SmbResponseStatus;
  1045. }
  1046. fUpdateVNetRootContext = TRUE;
  1047. NetRootState = SMBCEDB_INVALID;
  1048. }
  1049. // Note that the case wherein sufficient bytes are not indicated for the
  1050. // GENERIC_ANDX response is handled by the if statement below which
  1051. // imposes a more stringent test.
  1052. }
  1053. if ((Status == STATUS_SUCCESS) &&
  1054. (FIELD_OFFSET(RESP_21_TREE_CONNECT_ANDX,Buffer) + *pBytesConsumed) > BytesIndicated) {
  1055. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1056. }
  1057. if (Status == STATUS_SUCCESS) {
  1058. USHORT ResponseWordCount;
  1059. ULONG TreeConnectResponseLength,TreeConnectByteCount,ServiceStringLength;
  1060. PUCHAR pShareTypeResponseString = NULL;
  1061. PRESP_21_TREE_CONNECT_ANDX p21TreeConnectAndXResponse;
  1062. PUCHAR NativeFileSystem = NULL;
  1063. p21TreeConnectAndXResponse = (PRESP_21_TREE_CONNECT_ANDX)(pSmbBuffer);
  1064. SmbCommand = p21TreeConnectAndXResponse->AndXCommand;
  1065. TreeConnectByteCount = 0;
  1066. RxDbgTrace( 0, Dbg, ("Processing Tree Connect and X\n"));
  1067. // case out based on the actual response length. Lanman 21 clients or NT clients
  1068. // have a longer response.....win95 negotiates NT dialect but uses a <lm21 response format
  1069. ResponseWordCount = p21TreeConnectAndXResponse->WordCount;
  1070. switch (ResponseWordCount) {
  1071. case 0:
  1072. Status = SmbResponseStatus;
  1073. break;
  1074. case 3:
  1075. {
  1076. pNetRootEntry->MaximalAccessRights = FILE_ALL_ACCESS;
  1077. pNetRootEntry->GuestMaximalAccessRights = 0;
  1078. pShareTypeResponseString = (PUCHAR)&p21TreeConnectAndXResponse->Buffer;
  1079. TreeConnectByteCount = SmbGetUshort(&p21TreeConnectAndXResponse->ByteCount);
  1080. TreeConnectResponseLength =
  1081. FIELD_OFFSET(RESP_21_TREE_CONNECT_ANDX,Buffer) + TreeConnectByteCount;
  1082. NativeFileSystem = &p21TreeConnectAndXResponse->Buffer[3];
  1083. // Parse and update the optional support bits returned by
  1084. // the server
  1085. if (pServerEntry->Server.Dialect >= NTLANMAN_DIALECT ) {
  1086. USHORT OptionalSupport;
  1087. OptionalSupport = SmbGetUshort(
  1088. &p21TreeConnectAndXResponse->OptionalSupport);
  1089. if (FlagOn(OptionalSupport,SMB_SHARE_IS_IN_DFS)) {
  1090. PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
  1091. pNetRootEntry->NetRoot.DfsAware = TRUE;
  1092. SetFlag(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT);
  1093. }
  1094. }
  1095. if (SmbCommand == SMB_COM_NO_ANDX_COMMAND) {
  1096. Status = SmbResponseStatus;
  1097. } else {
  1098. TreeConnectResponseLength =
  1099. SmbGetUshort(&p21TreeConnectAndXResponse->AndXOffset) -
  1100. *pBytesConsumed;
  1101. }
  1102. }
  1103. break;
  1104. case 2:
  1105. {
  1106. PRESP_TREE_CONNECT_ANDX pTreeConnectAndXResponse;
  1107. pTreeConnectAndXResponse = (PRESP_TREE_CONNECT_ANDX)(pSmbBuffer);
  1108. ASSERT(FIELD_OFFSET(RESP_TREE_CONNECT_ANDX,AndXCommand)
  1109. ==FIELD_OFFSET(RESP_21_TREE_CONNECT_ANDX,AndXCommand));
  1110. pShareTypeResponseString = (PUCHAR)&pTreeConnectAndXResponse->Buffer;
  1111. TreeConnectByteCount = SmbGetUshort(&pTreeConnectAndXResponse->ByteCount);
  1112. TreeConnectResponseLength =
  1113. FIELD_OFFSET(RESP_TREE_CONNECT_ANDX,Buffer) + TreeConnectByteCount;
  1114. if (SmbCommand == SMB_COM_NO_ANDX_COMMAND) {
  1115. Status = SmbResponseStatus;
  1116. } else {
  1117. TreeConnectResponseLength =
  1118. SmbGetUshort(&pTreeConnectAndXResponse->AndXOffset) -
  1119. *pBytesConsumed;
  1120. }
  1121. // win9x server, returns wordcount of 2 yet has the dialect of NTLANMAN
  1122. // which is a bug, but we will work around it.
  1123. if (pServerEntry->Server.Dialect >= NTLANMAN_DIALECT ) {
  1124. pNetRootEntry->MaximalAccessRights = FILE_ALL_ACCESS;
  1125. pNetRootEntry->GuestMaximalAccessRights = 0;
  1126. }
  1127. }
  1128. break;
  1129. default :
  1130. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1131. }
  1132. RxDbgTrace( 0, Dbg, ("SmbCeParseSmbHeader::Tree connect and X Response %lx\n",Status));
  1133. if (NT_SUCCESS(Status)) {
  1134. PSMBCE_NET_ROOT psmbNetRoot = &(pNetRootEntry->NetRoot);
  1135. PSMBCE_SERVER psmbServer = &(pServerEntry->Server);
  1136. if (TreeConnectResponseLength + *pBytesConsumed <= BytesIndicated) {
  1137. *pBytesConsumed += TreeConnectResponseLength;
  1138. // Update the NetRoot fields based on the response.
  1139. SetFlag(
  1140. pVNetRootContext->Flags,
  1141. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  1142. RtlCopyMemory(
  1143. &pVNetRootContext->TreeId,
  1144. &pSmbHeader->Tid,
  1145. sizeof(pSmbHeader->Tid));
  1146. { struct __Service_Name_Entry *i;
  1147. for (i=ServiceNameTable;;i++) {
  1148. ServiceStringLength = i->NameLength;
  1149. if (TreeConnectByteCount >= ServiceStringLength) {
  1150. if (RtlCompareMemory(
  1151. pShareTypeResponseString,
  1152. i->Name,
  1153. ServiceStringLength)
  1154. == ServiceStringLength) {
  1155. psmbNetRoot->NetRootType = i->NetRootType;
  1156. if (FALSE) DbgPrint("FoundServiceStrng %s len %d type %d\n",i->Name,i->NameLength,i->NetRootType);
  1157. break;
  1158. }
  1159. }
  1160. if (i->NetRootType==NET_ROOT_COMM) {
  1161. ASSERT(!"Valid Share Type returned in TREE COnnect And X response");
  1162. psmbNetRoot->NetRootType = NET_ROOT_DISK;
  1163. ServiceStringLength = TreeConnectByteCount;
  1164. break;
  1165. }
  1166. }
  1167. }
  1168. if (psmbNetRoot->NetRootType == NET_ROOT_DISK) {
  1169. if (NativeFileSystem != NULL) {
  1170. if (BooleanFlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
  1171. if (RtlCompareMemory(
  1172. NativeFileSystem,
  1173. FileSystem_NTFS_UNICODE.Buffer,
  1174. FileSystem_NTFS_UNICODE.Length)
  1175. == FileSystem_NTFS_UNICODE.Length) {
  1176. psmbNetRoot->NetRootFileSystem = NET_ROOT_FILESYSTEM_NTFS;
  1177. } else if (RtlCompareMemory(
  1178. NativeFileSystem,
  1179. FileSystem_FAT_UNICODE.Buffer,
  1180. FileSystem_FAT_UNICODE.Length)
  1181. == FileSystem_FAT_UNICODE.Length) {
  1182. psmbNetRoot->NetRootFileSystem = NET_ROOT_FILESYSTEM_FAT;
  1183. }
  1184. } else {
  1185. if (RtlCompareMemory(
  1186. NativeFileSystem,
  1187. FileSystem_NTFS,
  1188. 4*sizeof(CHAR))
  1189. == 4*sizeof(CHAR)) {
  1190. psmbNetRoot->NetRootFileSystem = NET_ROOT_FILESYSTEM_NTFS;
  1191. } else if (RtlCompareMemory(
  1192. NativeFileSystem,
  1193. FileSystem_FAT,
  1194. 3*sizeof(CHAR))
  1195. == 3*sizeof(CHAR)) {
  1196. psmbNetRoot->NetRootFileSystem = NET_ROOT_FILESYSTEM_FAT;
  1197. }
  1198. }
  1199. }
  1200. psmbNetRoot->MaximumReadBufferSize = psmbServer->MaximumDiskFileReadBufferSize;
  1201. psmbNetRoot->MaximumWriteBufferSize = psmbServer->MaximumDiskFileWriteBufferSize;
  1202. } else {
  1203. psmbNetRoot->MaximumWriteBufferSize = psmbServer->MaximumNonDiskFileWriteBufferSize;
  1204. psmbNetRoot->MaximumReadBufferSize = psmbServer->MaximumNonDiskFileReadBufferSize;
  1205. }
  1206. //if !(NT was negotiated) and bytecount>servicelength, we may have a NativeFs name
  1207. if (!FlagOn(psmbServer->DialectFlags,DF_NTNEGOTIATE)
  1208. && (TreeConnectByteCount>ServiceStringLength)) {
  1209. PBYTE NativeFs = pShareTypeResponseString+ServiceStringLength;
  1210. if (*NativeFs != 0) {
  1211. ULONG i;
  1212. ULONG maxlenpersmb = TreeConnectByteCount-ServiceStringLength;
  1213. ULONG maxlenperarraysize = SMB_MAXIMUM_SUPPORTED_VOLUME_LABEL;
  1214. PCHAR p = (PCHAR)(&psmbNetRoot->FileSystemNameA[0]); //dont write into the 0th char
  1215. //DbgPrint("we may have one...\n");
  1216. for (i=1;;i++){
  1217. if (i==maxlenpersmb) {
  1218. break;
  1219. }
  1220. if (i==maxlenperarraysize) {
  1221. break;
  1222. }
  1223. if (NativeFs[i]==0) {
  1224. break;
  1225. }
  1226. }
  1227. //save away the name for processing later
  1228. RtlCopyMemory(p,NativeFs,i);
  1229. p[i] = 0;
  1230. //DbgPrint("NativeFs = %s (%d)\n",p,i);
  1231. psmbNetRoot->FileSystemNameALength = (UCHAR)i;
  1232. }
  1233. }
  1234. pSmbBuffer += TreeConnectResponseLength;
  1235. fUpdateVNetRootContext = TRUE;
  1236. NetRootState = SMBCEDB_ACTIVE;
  1237. } else {
  1238. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1239. }
  1240. } else {
  1241. fUpdateVNetRootContext = TRUE;
  1242. NetRootState = SMBCEDB_INVALID;
  1243. }
  1244. }
  1245. }
  1246. if ((SmbCommand == SMB_COM_TREE_CONNECT) &&
  1247. NT_SUCCESS(Status)) {
  1248. PRESP_TREE_CONNECT pTreeConnectResponse;
  1249. ULONG TreeConnectResponseLength;
  1250. RxDbgTrace( 0, Dbg, ("Processing Tree Connect\n"));
  1251. pTreeConnectResponse = (PRESP_TREE_CONNECT)pSmbBuffer;
  1252. TreeConnectResponseLength = FIELD_OFFSET(RESP_TREE_CONNECT,Buffer);
  1253. SmbCommand = SMB_COM_NO_ANDX_COMMAND;
  1254. if (NT_SUCCESS(SmbResponseStatus)) {
  1255. PSMBCE_NET_ROOT psmbNetRoot = &(pNetRootEntry->NetRoot);
  1256. PSMBCE_SERVER psmbServer = &(pServerEntry->Server);
  1257. if (TreeConnectResponseLength + *pBytesConsumed <= BytesIndicated) {
  1258. // Update the NetRoot fields based on the response.
  1259. SetFlag(
  1260. pVNetRootContext->Flags,
  1261. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  1262. RtlCopyMemory(
  1263. &pVNetRootContext->TreeId,
  1264. &pTreeConnectResponse->Tid,
  1265. sizeof(pTreeConnectResponse->Tid));
  1266. if (psmbServer->Dialect == PCNET1_DIALECT) {
  1267. psmbNetRoot->NetRootType = NET_ROOT_DISK;
  1268. }
  1269. else {
  1270. psmbNetRoot->NetRootType = NET_ROOT_WILD;
  1271. }
  1272. if (psmbServer->MaximumBufferSize == 0){
  1273. ULONG MaxBuf = SmbGetUshort(&pTreeConnectResponse->MaxBufferSize);
  1274. RxDbgTrace( 0, Dbg, ("SmbCeParseSmbHeader:: setting srvmaxbufsize %ld\n", MaxBuf));
  1275. psmbServer->MaximumBufferSize = MaxBuf;
  1276. //psmbServer->MaximumDiskFileReadBufferSize =
  1277. psmbNetRoot->MaximumWriteBufferSize =
  1278. psmbNetRoot->MaximumReadBufferSize =
  1279. MaxBuf -
  1280. QuadAlign(
  1281. sizeof(SMB_HEADER) +
  1282. FIELD_OFFSET(
  1283. RESP_READ,
  1284. Buffer[0]));
  1285. }
  1286. *pBytesConsumed += TreeConnectResponseLength;
  1287. pSmbBuffer += *pBytesConsumed;
  1288. fUpdateVNetRootContext = TRUE;
  1289. NetRootState = SMBCEDB_ACTIVE;
  1290. //for CORE, this counts as a successful session setup as well!
  1291. pSessionEntry->Session.UserId = pSmbHeader->Uid;
  1292. pExchange->SessionSetupStatus = STATUS_SUCCESS;
  1293. } else {
  1294. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1295. }
  1296. } else {
  1297. Status = SmbResponseStatus;
  1298. fUpdateVNetRootContext = TRUE;
  1299. NetRootState = SMBCEDB_MARKED_FOR_DELETION;
  1300. }
  1301. RxDbgTrace( 0, Dbg, ("SmbCeParseSmbHeader::Tree connect Response %lx\n",Status));
  1302. }
  1303. if ((SmbResponseStatus == STATUS_USER_SESSION_DELETED) ||
  1304. (SmbResponseStatus == STATUS_NETWORK_NAME_DELETED)) {
  1305. ClearFlag(
  1306. pVNetRootContext->Flags,
  1307. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  1308. InterlockedCompareExchange(
  1309. &(pVNetRootContext->Header.State),
  1310. SMBCEDB_INVALID,
  1311. SMBCEDB_ACTIVE);
  1312. InterlockedCompareExchange(
  1313. &(pSessionEntry->Header.State),
  1314. SMBCEDB_INVALID,
  1315. SMBCEDB_ACTIVE);
  1316. fUpdateVNetRootContext = TRUE;
  1317. NetRootState = SMBCEDB_INVALID;
  1318. }
  1319. // Initiate further action if the status of the exchange/conenction engine can be
  1320. // updated based on the data available.
  1321. if (fUpdateVNetRootContext) {
  1322. PMRX_NET_ROOT pNetRoot = pExchange->SmbCeContext.pVNetRoot->pNetRoot;
  1323. SmbCeUpdateVNetRootContextState(
  1324. pVNetRootContext,
  1325. NetRootState);
  1326. switch (NetRootState) {
  1327. case SMBCEDB_ACTIVE:
  1328. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
  1329. break;
  1330. case SMBCEDB_INVALID:
  1331. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_DISCONNECTED;
  1332. break;
  1333. case SMBCEDB_CONSTRUCTION_IN_PROGRESS:
  1334. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_RECONN;
  1335. break;
  1336. default:
  1337. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
  1338. break;
  1339. }
  1340. RxDbgTrace( 0, Dbg, ("Dispatching Net root Entry Finalization\n"));
  1341. }
  1342. IF_DEBUG {
  1343. if (!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) &&
  1344. !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR)) {
  1345. if ((pSmbHeader->Uid != pSessionEntry->Session.UserId) ||
  1346. (pSmbHeader->Tid != pVNetRootContext->TreeId)) {
  1347. RxLog(("Srvr %lx Xchg %lx RUid %ld RTid %ld\n SUid %ld STid %ld\n",
  1348. pServerEntry,pExchange,
  1349. pSmbHeader->Uid,pSmbHeader->Tid,
  1350. pSessionEntry->Session.UserId,pVNetRootContext->TreeId));
  1351. }
  1352. }
  1353. }
  1354. pExchange->SmbStatus = SmbResponseStatus; //N.B. no spinlock!
  1355. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1356. *pBytesConsumed = 0;
  1357. } else if (!NT_SUCCESS(Status)) {
  1358. *pBytesConsumed = BytesAvailable;
  1359. } else {
  1360. if (pSmbResponseStatus != NULL) {
  1361. *pSmbResponseStatus = SmbResponseStatus;
  1362. }
  1363. if (pCommandToProcess != NULL) {
  1364. PGENERIC_ANDX pGenericAndX = (PGENERIC_ANDX)((PBYTE)pSmbHeader + *pBytesConsumed);
  1365. pCommandToProcess->AndXCommand = SmbCommand;
  1366. SmbPutUshort(&pCommandToProcess->AndXOffset, (USHORT)*pBytesConsumed);
  1367. if ((sizeof(GENERIC_ANDX) + *pBytesConsumed) <= BytesAvailable) {
  1368. pCommandToProcess->WordCount = pGenericAndX->WordCount;
  1369. } else {
  1370. pCommandToProcess->WordCount = 0;
  1371. }
  1372. }
  1373. }
  1374. return Status;
  1375. }
  1376. NTSTATUS
  1377. SmbCeResumeExchange(
  1378. PSMB_EXCHANGE pExchange)
  1379. /*++
  1380. Routine Description:
  1381. This routine resumes an exchange that was suspended in the connection
  1382. engine
  1383. Arguments:
  1384. pExchange - the exchange Instance
  1385. Return Value:
  1386. The return status for the operation
  1387. --*/
  1388. {
  1389. NTSTATUS Status;
  1390. PAGED_CODE();
  1391. SmbCeIncrementPendingLocalOperations(pExchange);
  1392. // Initiate the exchange
  1393. Status = SmbCeInitiateExchange(pExchange);
  1394. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  1395. return Status;
  1396. }
  1397. NTSTATUS
  1398. SmbCepInitializeExchange(
  1399. PSMB_EXCHANGE *pExchangePointer,
  1400. PRX_CONTEXT pRxContext,
  1401. PSMBCEDB_SERVER_ENTRY pServerEntry,
  1402. PMRX_V_NET_ROOT pVNetRoot,
  1403. SMB_EXCHANGE_TYPE Type,
  1404. PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector)
  1405. /*++
  1406. Routine Description:
  1407. This routine initializes the given exchange instanece
  1408. Arguments:
  1409. pExchangePointer - the placeholder for the exchange instance. If it is NULL a new one
  1410. is allocated.
  1411. pRxContext - the associated RxContext
  1412. pServerEntry - the associated server entry
  1413. pVirtualNetRoot - the virtual net root
  1414. Type - the type of the exchange
  1415. pDispatchVector - the dispatch vector asscoiated with this instance.
  1416. Return Value:
  1417. RXSTATUS - The return status for the operation
  1418. --*/
  1419. {
  1420. NTSTATUS Status = STATUS_SUCCESS;
  1421. PSMB_EXCHANGE pExchange = NULL;
  1422. PAGED_CODE();
  1423. RxDbgTrace( 0, Dbg, ("SmbCeInitializeExchange: Invoked\n"));
  1424. if (*pExchangePointer == NULL) {
  1425. // Allocate a new exchange instance.
  1426. pExchange = SmbMmAllocateExchange(Type,NULL);
  1427. if (pExchange == NULL) {
  1428. return STATUS_INSUFFICIENT_RESOURCES;
  1429. }
  1430. *pExchangePointer = pExchange;
  1431. }
  1432. if ((Status = SmbCeIncrementActiveExchangeCount()) == STATUS_SUCCESS) {
  1433. PSMB_EXCHANGE LocalExchangePointer = *pExchangePointer;
  1434. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1435. LocalExchangePointer->CancellationStatus = SMBCE_EXCHANGE_NOT_CANCELLED;
  1436. LocalExchangePointer->RxContext = pRxContext;
  1437. if (Status == STATUS_SUCCESS) {
  1438. if (pVNetRoot != NULL) {
  1439. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
  1440. LocalExchangePointer->SmbCeContext.pVNetRoot = pVNetRoot;
  1441. pServerEntry = SmbCeGetAssociatedServerEntry(pVNetRoot->pNetRoot->pSrvCall);
  1442. } else {
  1443. ASSERT(pServerEntry != NULL);
  1444. pVNetRootContext = NULL;
  1445. }
  1446. if (pVNetRootContext != NULL) {
  1447. SmbCeReferenceVNetRootContext(pVNetRootContext);
  1448. LocalExchangePointer->SmbCeContext.pVNetRootContext =
  1449. pVNetRootContext;
  1450. LocalExchangePointer->SmbCeContext.pServerEntry =
  1451. pVNetRootContext->pServerEntry;
  1452. } else {
  1453. SmbCeReferenceServerEntry(pServerEntry);
  1454. LocalExchangePointer->SmbCeContext.pServerEntry =
  1455. pServerEntry;
  1456. LocalExchangePointer->SmbCeContext.pVNetRootContext = NULL;
  1457. }
  1458. LocalExchangePointer->SmbCeState = SMBCE_EXCHANGE_INITIALIZATION_START;
  1459. LocalExchangePointer->pDispatchVector = pDispatchVector;
  1460. LocalExchangePointer->SmbCeFlags &= (SMBCE_EXCHANGE_FLAGS_TO_PRESERVE);
  1461. LocalExchangePointer->SmbCeFlags |= (SMBCE_EXCHANGE_REUSE_MID | SMBCE_EXCHANGE_ATTEMPT_RECONNECTS);
  1462. }
  1463. if (Status != STATUS_SUCCESS) {
  1464. SmbCeDecrementActiveExchangeCount();
  1465. }
  1466. } else {
  1467. (*pExchangePointer)->SmbCeFlags |= SMBCE_EXCHANGE_SMBCE_STOPPED;
  1468. }
  1469. if (!NT_SUCCESS(Status)) {
  1470. if (pExchange != NULL) {
  1471. SmbMmFreeExchange(pExchange);
  1472. *pExchangePointer = NULL;
  1473. }
  1474. }
  1475. return Status;
  1476. }
  1477. NTSTATUS
  1478. SmbCeInitializeAssociatedExchange(
  1479. PSMB_EXCHANGE *pAssociatedExchangePointer,
  1480. PSMB_EXCHANGE pMasterExchange,
  1481. SMB_EXCHANGE_TYPE Type,
  1482. PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector)
  1483. /*++
  1484. Routine Description:
  1485. This routine initializes the given exchange instanece
  1486. Arguments:
  1487. pAssociatedExchangePointer - the placeholder for the exchange instance. If it is NULL a new one
  1488. is allocated.
  1489. pMasterExchange - the master exchange
  1490. Type - the type of the exchange
  1491. pDispatchVector - the dispatch vector asscoiated with this instance.
  1492. Return Value:
  1493. NTSTATUS - The return status for the operation
  1494. Notes:
  1495. --*/
  1496. {
  1497. NTSTATUS Status = STATUS_SUCCESS;
  1498. PAGED_CODE();
  1499. if ((pMasterExchange->SmbCeState == SMBCE_EXCHANGE_INITIATED) &&
  1500. !FlagOn(pMasterExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE)) {
  1501. Status = SmbCeInitializeExchange(
  1502. pAssociatedExchangePointer,
  1503. NULL,
  1504. pMasterExchange->SmbCeContext.pVNetRoot,
  1505. Type,
  1506. pDispatchVector);
  1507. if (Status == STATUS_SUCCESS) {
  1508. PSMB_EXCHANGE pAssociatedExchange;
  1509. pAssociatedExchange = *pAssociatedExchangePointer;
  1510. pAssociatedExchange->SmbCeState = SMBCE_EXCHANGE_INITIATED;
  1511. pAssociatedExchange->SmbCeFlags |= SMBCE_ASSOCIATED_EXCHANGE;
  1512. SmbCeIncrementPendingLocalOperations(pMasterExchange);
  1513. InterlockedIncrement(&pMasterExchange->Master.PendingAssociatedExchanges);
  1514. pAssociatedExchange->Associated.pMasterExchange = pMasterExchange;
  1515. InitializeListHead(&pAssociatedExchange->WorkQueueItem.List);
  1516. }
  1517. } else {
  1518. Status = STATUS_INVALID_PARAMETER;
  1519. }
  1520. return Status;
  1521. }
  1522. NTSTATUS
  1523. SmbCeTransformExchange(
  1524. PSMB_EXCHANGE pExchange,
  1525. SMB_EXCHANGE_TYPE NewType,
  1526. PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector)
  1527. /*++
  1528. Routine Description:
  1529. This routine transforms an exchange instance of one kind to an exchange instance
  1530. of another kind ( A sophisticated form of casting )
  1531. Arguments:
  1532. pExchange - the exchange instance.
  1533. Type - the new type of the exchange
  1534. pDispatchVector - the dispatch vector asscoiated with this instance.
  1535. Return Value:
  1536. RXSTATUS - The return status for the operation
  1537. Notes:
  1538. As it is currently implemented no restrictions are imposed. Once the number of exchanges
  1539. have been established further restrictions will be imposed barring certain kinds of
  1540. transformations. The transformation merely switches the dispatch vector associated
  1541. with the exchange but the context is left intact.
  1542. --*/
  1543. {
  1544. PAGED_CODE();
  1545. pExchange->Type = (UCHAR)NewType;
  1546. pExchange->pDispatchVector = pDispatchVector;
  1547. return STATUS_SUCCESS;
  1548. }
  1549. NTSTATUS
  1550. SmbCePrepareExchangeForReuse(
  1551. PSMB_EXCHANGE pExchange)
  1552. /*++
  1553. Routine Description:
  1554. This routine transforms an exchange instance of one kind to an exchange instance
  1555. of another kind ( A sophisticated form of casting )
  1556. Arguments:
  1557. pExchange - the exchange instance.
  1558. Return Value:
  1559. RXSTATUS - The return status for the operation
  1560. --*/
  1561. {
  1562. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  1563. PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
  1564. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  1565. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  1566. PAGED_CODE();
  1567. RxDbgTrace( 0, Dbg, ("SmbCePrepareExchangeForReuse: Invoked\n"));
  1568. if (!FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_SMBCE_STOPPED)) {
  1569. pNetRootEntry = SmbCeGetExchangeNetRootEntry(pExchange);
  1570. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  1571. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  1572. pVNetRootContext = SmbCeGetExchangeVNetRootContext(pExchange);
  1573. if (pServerEntry != NULL) {
  1574. // Disassociate the MID associated with the exchange
  1575. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
  1576. SmbCeDissociateMidFromExchange(pServerEntry,pExchange);
  1577. }
  1578. // Tear down all the copy data requests associated with this exchange
  1579. SmbCePurgeBuffersAssociatedWithExchange(pServerEntry,pExchange);
  1580. // Uninitialize the transport associated with the exchange
  1581. SmbCeUninitializeExchangeTransport(pExchange);
  1582. }
  1583. // If this exchange has been marked as a constructor for either a
  1584. // session or netroot finalize the appropriate entries. ( mark
  1585. // them for deletion so that other exchanges can be resumed )
  1586. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) {
  1587. ASSERT(pSessionEntry != NULL);
  1588. RxDbgTrace( 0, Dbg, ("Dispatching Session Entry Finalization\n"));
  1589. SmbCeReferenceSessionEntry(pSessionEntry);
  1590. ASSERT(pExchange->SessionSetupStatus != STATUS_SUCCESS ||
  1591. pSessionEntry->Header.State == SMBCEDB_CONSTRUCTION_IN_PROGRESS);
  1592. SmbCeCompleteSessionEntryInitialization(pSessionEntry,pExchange->SessionSetupStatus);
  1593. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
  1594. }
  1595. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR) {
  1596. ASSERT(pVNetRootContext != NULL);
  1597. RxDbgTrace( 0, Dbg, ("Dispatching Net root Entry Finalization\n"));
  1598. SmbCeReferenceVNetRootContext(pVNetRootContext);
  1599. SmbCeCompleteVNetRootContextInitialization(pVNetRootContext);
  1600. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR;
  1601. }
  1602. if (pVNetRootContext != NULL) {
  1603. SmbCeDereferenceVNetRootContext(pVNetRootContext);
  1604. } else {
  1605. if (pServerEntry != NULL) {
  1606. SmbCeDereferenceServerEntry(pServerEntry);
  1607. }
  1608. }
  1609. }
  1610. if (FlagOn(pExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE)) {
  1611. PSMB_EXCHANGE pMasterExchange;
  1612. LONG AssociatedExchangeCount;
  1613. pMasterExchange = pExchange->Associated.pMasterExchange;
  1614. AssociatedExchangeCount = InterlockedDecrement(
  1615. &pMasterExchange->Master.PendingAssociatedExchanges);
  1616. if (FlagOn(
  1617. pMasterExchange->SmbCeFlags,
  1618. SMBCE_ASSOCIATED_EXCHANGES_COMPLETION_HANDLER_ACTIVATED) &&
  1619. (AssociatedExchangeCount == 0)){
  1620. NTSTATUS Status;
  1621. BOOLEAN PostRequest;
  1622. ClearFlag(
  1623. pMasterExchange->SmbCeFlags,
  1624. SMBCE_ASSOCIATED_EXCHANGES_COMPLETION_HANDLER_ACTIVATED);
  1625. Status = SMB_EXCHANGE_DISPATCH(
  1626. pMasterExchange,
  1627. AssociatedExchangesCompletionHandler,
  1628. (pMasterExchange,&PostRequest));
  1629. RxDbgTrace(0,Dbg,("Master Exchange %lx Assoc. Completion Status %lx\n",pMasterExchange,Status));
  1630. }
  1631. SmbCeDecrementPendingLocalOperationsAndFinalize(pMasterExchange);
  1632. }
  1633. return STATUS_SUCCESS;
  1634. }
  1635. VOID
  1636. SmbCeDiscardExchangeWorkerThreadRoutine(PVOID pExchange)
  1637. /*++
  1638. Routine Description:
  1639. This routine discards an exchange.
  1640. Arguments:
  1641. pExchange - the exchange to be discarded.
  1642. Return Value:
  1643. RXSTATUS - The return status for the operation
  1644. Notes:
  1645. Even though this is simple, it cannot be inlined since the destruction of an
  1646. exchange instance can be posted to a waorker thread.
  1647. --*/
  1648. {
  1649. PSMB_EXCHANGE pSmbExchange = pExchange;
  1650. PAGED_CODE();
  1651. RxDbgTrace( 0, Dbg, ("SmbCeDiscardExchange: Invoked\n"));
  1652. //RxLog((">>>Discard %lx",pSmbExchange));
  1653. // Destory the context
  1654. if (pSmbExchange->ReferenceCount == 0) {
  1655. SmbCeAcquireResource();
  1656. RemoveEntryList(&pSmbExchange->ExchangeList);
  1657. SmbCeReleaseResource();
  1658. SmbCePrepareExchangeForReuse(pSmbExchange);
  1659. SmbCeDecrementActiveExchangeCount();
  1660. // Discard the memory associated with the exchange
  1661. SmbMmFreeExchange(pSmbExchange);
  1662. } else {
  1663. RxDbgTrace(
  1664. 0,
  1665. Dbg,
  1666. ("SmbCeDiscardExchange: Exchange %lx not discarded %ld\n",
  1667. pSmbExchange,pSmbExchange->ReferenceCount)
  1668. );
  1669. }
  1670. }
  1671. VOID
  1672. SmbCeDiscardExchange(PVOID pExchange)
  1673. /*++
  1674. Routine Description:
  1675. This routine discards an exchange.
  1676. Arguments:
  1677. pExchange - the exchange to be discarded.
  1678. Notes:
  1679. The destruction of an exchange instance is posted to a worker thread in order to
  1680. avoid deadlock in transport.
  1681. --*/
  1682. {
  1683. PSMB_EXCHANGE pSmbExchange = pExchange;
  1684. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pSmbExchange);
  1685. // Disassociate the MID associated with the exchange
  1686. if (pSmbExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
  1687. SmbCeDissociateMidFromExchange(pServerEntry,pSmbExchange);
  1688. }
  1689. RxPostToWorkerThread(
  1690. MRxSmbDeviceObject,
  1691. CriticalWorkQueue,
  1692. &((PSMB_EXCHANGE)pExchange)->WorkQueueItem,
  1693. SmbCeDiscardExchangeWorkerThreadRoutine,
  1694. (PSMB_EXCHANGE)pExchange);
  1695. }
  1696. NTSTATUS
  1697. SmbCeCancelExchange(
  1698. PRX_CONTEXT pRxContext)
  1699. /*++
  1700. Routine Description:
  1701. This routine initiates the cancellation of an exchange.
  1702. Arguments:
  1703. pRxContext - the RX_CONTEXT instance for which cancellation needs to be
  1704. initiated.
  1705. Return Value:
  1706. NTSTATUS - The return status for the operation
  1707. Notes:
  1708. The cancellation policy that has been implemented is a "best effort" policy.
  1709. Since the server has already committed resources to an operation at its end
  1710. the best that we can do within the scope of the SMB protocol is to initiate
  1711. a cancellation operation by sending the appropriate SMB_COM_NT_CANCEL command
  1712. Not all dialects of SMB support this command. For the downlevel dialects the
  1713. best that we can do is to ensure that the MID is not reused during the lifetime
  1714. of the connection. This will result in a gradual degradation of performance.
  1715. The difficulty in detecting the end of operations is that there are MIDS
  1716. --*/
  1717. {
  1718. NTSTATUS Status = STATUS_SUCCESS;
  1719. PSMB_EXCHANGE pExchange;
  1720. PMRXSMB_RX_CONTEXT pMRxSmbContext;
  1721. SmbCeLog(("SmbCe Cancel %lx\n",pRxContext));
  1722. SmbCeAcquireSpinLock();
  1723. pMRxSmbContext = MRxSmbGetMinirdrContext(pRxContext);
  1724. pExchange = (PSMB_EXCHANGE)pMRxSmbContext->pCancelContext;
  1725. if (pExchange != NULL) {
  1726. if (!FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED)) {
  1727. if (pExchange->ReceivePendingOperations > 0) {
  1728. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1729. // This exchange is awaiting a response from the server. In all
  1730. // these cases a CANCEL command needs to be sent to the server
  1731. // This command can only be sent to NT servers. For non NT
  1732. // servers this exchange can be terminated with the detrimental
  1733. // side effect of reducing the maximum number of commands by 1.
  1734. InterlockedIncrement(&pExchange->LocalPendingOperations);
  1735. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1736. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  1737. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  1738. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
  1739. NTSTATUS LocalStatus;
  1740. LocalStatus = SmbCepDiscardMidAssociatedWithExchange(
  1741. pExchange);
  1742. ASSERT(LocalStatus == STATUS_SUCCESS);
  1743. }
  1744. }
  1745. } else {
  1746. InterlockedCompareExchange(
  1747. &pExchange->CancellationStatus,
  1748. SMBCE_EXCHANGE_CANCELLED,
  1749. SMBCE_EXCHANGE_NOT_CANCELLED);
  1750. }
  1751. }
  1752. }
  1753. SmbCeReleaseSpinLock();
  1754. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1755. PSMBCE_SERVER pServer;
  1756. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1757. SmbCeLog(("SmbCeCancel Initiate %lx\n",pExchange));
  1758. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  1759. pServer = SmbCeGetExchangeServer(pExchange);
  1760. if (FlagOn(pServer->DialectFlags,DF_NT_SMBS)) {
  1761. UCHAR LastCommandInHeader;
  1762. PUCHAR pCommand;
  1763. PSMB_HEADER pSmbHeader;
  1764. PNT_SMB_HEADER pNtSmbHeader;
  1765. #define CANCEL_BUFFER_SIZE (sizeof(SMB_HEADER) + sizeof(REQ_NT_CANCEL))
  1766. BYTE SmbBuffer[TRANSPORT_HEADER_SIZE + CANCEL_BUFFER_SIZE];
  1767. PBYTE CancelRequestBuffer = SmbBuffer + TRANSPORT_HEADER_SIZE;
  1768. ULONG CancelRequestBufferSize = CANCEL_BUFFER_SIZE;
  1769. pSmbHeader = (PSMB_HEADER)CancelRequestBuffer;
  1770. pNtSmbHeader = (PNT_SMB_HEADER)pSmbHeader;
  1771. // Before issuing the cancel request ensure that if this exchange
  1772. // is set as a timed receive operation. This will ensure that if
  1773. // the cancel is delayed at the server we will initiate a tear down
  1774. // of the connection.
  1775. if (!FlagOn(
  1776. pExchange->SmbCeFlags,
  1777. SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION)) {
  1778. SmbCeAcquireResource();
  1779. SmbCeSetExpiryTime(pExchange);
  1780. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION;
  1781. SmbCeReleaseResource();
  1782. }
  1783. // Build the Cancel request and send it across to the server.
  1784. Status = SmbCeBuildSmbHeader(
  1785. pExchange,
  1786. CancelRequestBuffer,
  1787. CancelRequestBufferSize,
  1788. &CancelRequestBufferSize,
  1789. &LastCommandInHeader,
  1790. &pCommand);
  1791. ASSERT(LastCommandInHeader == SMB_COM_NO_ANDX_COMMAND);
  1792. if (Status == STATUS_SUCCESS) {
  1793. PREQ_NT_CANCEL pCancelRequest = (PREQ_NT_CANCEL)(&CancelRequestBuffer[sizeof(SMB_HEADER)]);
  1794. PMDL pCancelSmbMdl;
  1795. *pCommand = SMB_COM_NT_CANCEL;
  1796. SmbPutUshort(&pSmbHeader->Mid,pExchange->Mid);
  1797. if (BooleanFlagOn(
  1798. pExchange->SmbCeFlags,
  1799. SMBCE_EXCHANGE_FULL_PROCESSID_SPECIFIED)) {
  1800. ULONG ProcessId;
  1801. ProcessId = RxGetRequestorProcessId(pRxContext);
  1802. SmbPutUshort(&pNtSmbHeader->Pid, (USHORT)((ProcessId) & 0xFFFF));
  1803. SmbPutUshort(&pNtSmbHeader->PidHigh, (USHORT)((ProcessId) >> 16));
  1804. }
  1805. SmbPutUshort(&pCancelRequest->WordCount,0);
  1806. pCancelRequest->ByteCount = 0;
  1807. CancelRequestBufferSize = CANCEL_BUFFER_SIZE;
  1808. RxAllocateHeaderMdl(
  1809. CancelRequestBuffer,
  1810. CancelRequestBufferSize,
  1811. pCancelSmbMdl
  1812. );
  1813. if (pCancelSmbMdl != NULL) {
  1814. RxProbeAndLockHeaderPages(
  1815. pCancelSmbMdl,
  1816. KernelMode,
  1817. IoModifyAccess,
  1818. Status);
  1819. if (Status == STATUS_SUCCESS) {
  1820. Status = SmbCeSendToServer(
  1821. pServerEntry,
  1822. RXCE_SEND_SYNCHRONOUS,
  1823. pCancelSmbMdl,
  1824. CancelRequestBufferSize);
  1825. RxUnlockHeaderPages(pCancelSmbMdl);
  1826. }
  1827. IoFreeMdl(pCancelSmbMdl);
  1828. }
  1829. }
  1830. } else {
  1831. SmbCeFinalizeExchangeOnDisconnect(pExchange);
  1832. }
  1833. InterlockedCompareExchange(
  1834. &pExchange->CancellationStatus,
  1835. SMBCE_EXCHANGE_CANCELLED,
  1836. SMBCE_EXCHANGE_NOT_CANCELLED);
  1837. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  1838. }
  1839. return Status;
  1840. }
  1841. NTSTATUS
  1842. SmbCeIncrementPendingOperations(
  1843. PSMB_EXCHANGE pExchange,
  1844. ULONG PendingOperationMask,
  1845. PVOID FileName,
  1846. ULONG FileLine)
  1847. /*++
  1848. Routine Description:
  1849. This routine increments the appropriate pending operation count
  1850. Arguments:
  1851. pExchange - the exchange to be finalized.
  1852. PendingOperationsMask -- the pending operations to be incremented
  1853. Return Value:
  1854. RxStatus(SUCCESS) if successful
  1855. --*/
  1856. {
  1857. NTSTATUS Status;
  1858. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1859. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  1860. SmbCeAcquireSpinLock();
  1861. if (!BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED)) {
  1862. if ((pServerEntry != NULL) &&
  1863. ((pServerEntry->ServerStatus == STATUS_SUCCESS) ||
  1864. (pExchange->NodeTypeCode == SMB_EXCHANGE_NTC(ADMIN_EXCHANGE)))) {
  1865. if (PendingOperationMask & SMBCE_LOCAL_OPERATION) {
  1866. pExchange->LocalPendingOperations++;
  1867. }
  1868. if (PendingOperationMask & SMBCE_SEND_COMPLETE_OPERATION) {
  1869. pExchange->SendCompletePendingOperations++;
  1870. }
  1871. if (PendingOperationMask & SMBCE_COPY_DATA_OPERATION) {
  1872. pExchange->CopyDataPendingOperations++;
  1873. }
  1874. if (PendingOperationMask & SMBCE_RECEIVE_OPERATION) {
  1875. pExchange->ReceivePendingOperations++;
  1876. }
  1877. Status = STATUS_SUCCESS;
  1878. } else {
  1879. if ((PendingOperationMask & SMBCE_LOCAL_OPERATION) &&
  1880. (PendingOperationMask & ~SMBCE_LOCAL_OPERATION) == 0) {
  1881. pExchange->LocalPendingOperations++;
  1882. Status = STATUS_SUCCESS;
  1883. } else {
  1884. Status = STATUS_CONNECTION_DISCONNECTED;
  1885. }
  1886. }
  1887. } else {
  1888. Status = STATUS_UNSUCCESSFUL;
  1889. }
  1890. SmbCeReleaseSpinLock();
  1891. return Status;
  1892. }
  1893. VOID
  1894. SmbCeFinalizeExchangeWorkerThreadRoutine(
  1895. PSMB_EXCHANGE pExchange)
  1896. /*++
  1897. Routine Description:
  1898. This is the worker thread exchange finalization routine.
  1899. Arguments:
  1900. pExchange - the exchange to be finalized.
  1901. --*/
  1902. {
  1903. BOOLEAN fPostFinalize;
  1904. NTSTATUS Status;
  1905. PAGED_CODE();
  1906. Status = SMB_EXCHANGE_DISPATCH(
  1907. pExchange,
  1908. Finalize,
  1909. (pExchange,&fPostFinalize));
  1910. ASSERT(!fPostFinalize && (Status == STATUS_SUCCESS));
  1911. }
  1912. VOID
  1913. SmbCepFinalizeExchange(
  1914. PSMB_EXCHANGE pExchange)
  1915. /*++
  1916. Routine Description:
  1917. This is the common finalization routine used by both the routines below
  1918. Arguments:
  1919. pExchange - the exchange to be finalized.
  1920. --*/
  1921. {
  1922. BOOLEAN fAssociatedExchange;
  1923. ASSERT(FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED));
  1924. fAssociatedExchange = BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE);
  1925. if (fAssociatedExchange) {
  1926. PSMB_EXCHANGE pMasterExchange;
  1927. // The local operation will be decremented on resumption of
  1928. // the finalization routine
  1929. pMasterExchange = pExchange->Associated.pMasterExchange;
  1930. SmbCeIncrementPendingLocalOperations(pMasterExchange);
  1931. RxPostToWorkerThread(
  1932. MRxSmbDeviceObject,
  1933. CriticalWorkQueue,
  1934. &pExchange->WorkQueueItem,
  1935. SmbCepFinalizeAssociatedExchange,
  1936. pExchange);
  1937. } else {
  1938. NTSTATUS Status;
  1939. BOOLEAN fPostFinalize = FALSE;
  1940. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1941. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  1942. pExchange->ExpiryTime.QuadPart = 0;
  1943. if (!FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_RETAIN_MID)) {
  1944. SmbCeDissociateMidFromExchange(
  1945. pServerEntry,
  1946. pExchange);
  1947. }
  1948. Status = SMB_EXCHANGE_DISPATCH(
  1949. pExchange,
  1950. Finalize,
  1951. (pExchange,&fPostFinalize));
  1952. if ((Status == STATUS_SUCCESS) &&
  1953. fPostFinalize) {
  1954. // Post the request to a worker thread so that the finalization can be completed
  1955. // at a lower IRQL.
  1956. RxPostToWorkerThread(
  1957. MRxSmbDeviceObject,
  1958. CriticalWorkQueue,
  1959. &pExchange->WorkQueueItem,
  1960. SmbCeFinalizeExchangeWorkerThreadRoutine,
  1961. pExchange);
  1962. }
  1963. }
  1964. }
  1965. #define SENTINEL_ENTRY ((PSINGLE_LIST_ENTRY)IntToPtr(0xffffffff))
  1966. VOID
  1967. SmbCepFinalizeAssociatedExchange(
  1968. PSMB_EXCHANGE pExchange)
  1969. /*++
  1970. Routine Description:
  1971. This is the common finalization routine used by both the routines below
  1972. Arguments:
  1973. pExchange - the exchange to be finalized.
  1974. --*/
  1975. {
  1976. PSMB_EXCHANGE pMasterExchange;
  1977. PSMB_EXCHANGE pAssociatedExchange;
  1978. SINGLE_LIST_ENTRY AssociatedExchangeList;
  1979. ASSERT(FlagOn(pExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE));
  1980. pMasterExchange = pExchange->Associated.pMasterExchange;
  1981. ASSERT(pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next != NULL);
  1982. for (;;) {
  1983. BOOLEAN fAllAssociatedExchangesFinalized = FALSE;
  1984. SmbCeAcquireSpinLock();
  1985. if (pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next == SENTINEL_ENTRY) {
  1986. pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next = NULL;
  1987. fAllAssociatedExchangesFinalized = TRUE;
  1988. } else if (pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next == NULL) {
  1989. fAllAssociatedExchangesFinalized = TRUE;
  1990. } else {
  1991. AssociatedExchangeList.Next =
  1992. pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next;
  1993. pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next =
  1994. SENTINEL_ENTRY;
  1995. }
  1996. SmbCeReleaseSpinLock();
  1997. if (!fAllAssociatedExchangesFinalized) {
  1998. for (;;) {
  1999. PSINGLE_LIST_ENTRY pAssociatedExchangeEntry;
  2000. pAssociatedExchangeEntry = AssociatedExchangeList.Next;
  2001. if ((pAssociatedExchangeEntry != NULL) &&
  2002. (pAssociatedExchangeEntry != SENTINEL_ENTRY)) {
  2003. NTSTATUS Status;
  2004. BOOLEAN fPostFinalize = FALSE;
  2005. AssociatedExchangeList.Next = pAssociatedExchangeEntry->Next;
  2006. pAssociatedExchange = (PSMB_EXCHANGE)
  2007. CONTAINING_RECORD(
  2008. pAssociatedExchangeEntry,
  2009. SMB_EXCHANGE,
  2010. Associated.NextAssociatedExchange);
  2011. ASSERT(IsListEmpty(&pAssociatedExchange->WorkQueueItem.List));
  2012. Status = SMB_EXCHANGE_DISPATCH(
  2013. pAssociatedExchange,
  2014. Finalize,
  2015. (pAssociatedExchange,&fPostFinalize));
  2016. } else {
  2017. break;
  2018. }
  2019. };
  2020. } else {
  2021. break;
  2022. }
  2023. }
  2024. SmbCeDecrementPendingLocalOperationsAndFinalize(pMasterExchange);
  2025. }
  2026. BOOLEAN
  2027. SmbCeCanExchangeBeFinalized(
  2028. PSMB_EXCHANGE pExchange,
  2029. PSMBCE_EXCHANGE_STATUS pExchangeStatus)
  2030. /*++
  2031. Routine Description:
  2032. This routine determines if the exchange instance can be finalized.
  2033. Arguments:
  2034. pExchange - the exchange to be finalized.
  2035. pExchangeStatus - the finalization status
  2036. Return Value:
  2037. TRUE if the exchange can be finalized
  2038. Notes:
  2039. As a side effect it also sets the SMBCE_EXCHANGE_FINALIZED flag
  2040. The SmbCe spin lock must have been acquire on entry
  2041. --*/
  2042. {
  2043. BOOLEAN fFinalizeExchange = FALSE;
  2044. BOOLEAN fAssociatedExchange;
  2045. fAssociatedExchange = BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_ASSOCIATED_EXCHANGE);
  2046. if (!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_FINALIZED)) {
  2047. if ((pExchange->ReceivePendingOperations == 0) &&
  2048. (pExchange->CopyDataPendingOperations == 0) &&
  2049. (pExchange->SendCompletePendingOperations == 0) &&
  2050. (pExchange->LocalPendingOperations == 0)) {
  2051. fFinalizeExchange = TRUE;
  2052. *pExchangeStatus = SmbCeExchangeFinalized;
  2053. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_FINALIZED;
  2054. if (fAssociatedExchange) {
  2055. PSMB_EXCHANGE pMasterExchange = pExchange->Associated.pMasterExchange;
  2056. if (pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next != NULL) {
  2057. fFinalizeExchange = FALSE;
  2058. }
  2059. pExchange->Associated.NextAssociatedExchange.Next =
  2060. pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next;
  2061. pMasterExchange->Master.AssociatedExchangesToBeFinalized.Next =
  2062. &pExchange->Associated.NextAssociatedExchange;
  2063. }
  2064. } else {
  2065. *pExchangeStatus = SmbCeExchangeNotFinalized;
  2066. }
  2067. } else {
  2068. *pExchangeStatus = SmbCeExchangeAlreadyFinalized;
  2069. }
  2070. if (fFinalizeExchange &&
  2071. (pExchange->RxContext != NULL)) {
  2072. NTSTATUS Status;
  2073. PMRXSMB_RX_CONTEXT pMRxSmbContext;
  2074. pMRxSmbContext = MRxSmbGetMinirdrContext(pExchange->RxContext);
  2075. pMRxSmbContext->pCancelContext = NULL;
  2076. Status = RxSetMinirdrCancelRoutine(
  2077. pExchange->RxContext,
  2078. NULL);
  2079. }
  2080. return fFinalizeExchange;
  2081. }
  2082. SMBCE_EXCHANGE_STATUS
  2083. SmbCeFinalizeExchange(
  2084. PSMB_EXCHANGE pExchange)
  2085. /*++
  2086. Routine Description:
  2087. This routine finalizes an exchange instance.
  2088. Arguments:
  2089. pExchange - the exchange to be finalized.
  2090. Return Value:
  2091. appropriate exchange status
  2092. Notes:
  2093. When an exchange is initiated and the start routine is invoked a number of
  2094. SMB's are sent. This routine is invoked when all processing pertaining to the
  2095. SMB's that have been sent has ceased.
  2096. This routine encapsulates all the idiosyncratic behaviour associated with the
  2097. transports.
  2098. --*/
  2099. {
  2100. BOOLEAN fFinalizeExchange = FALSE;
  2101. SMBCE_EXCHANGE_STATUS ExchangeStatus;
  2102. SmbCeAcquireSpinLock();
  2103. fFinalizeExchange = SmbCeCanExchangeBeFinalized(
  2104. pExchange,
  2105. &ExchangeStatus);
  2106. SmbCeReleaseSpinLock();
  2107. if (fFinalizeExchange) {
  2108. SmbCepFinalizeExchange(pExchange);
  2109. }
  2110. return ExchangeStatus;
  2111. }
  2112. NTSTATUS
  2113. SmbCeDecrementPendingOperations(
  2114. PSMB_EXCHANGE pExchange,
  2115. ULONG PendingOperationMask,
  2116. PVOID FileName,
  2117. ULONG FileLine)
  2118. /*++
  2119. Routine Description:
  2120. This routine decrements the corresponding pending operation count
  2121. and finalizes an exchange instance if required
  2122. Arguments:
  2123. pExchange - the exchange to be finalized.
  2124. PendingOperationsMask -- the pending operations to be decremented.
  2125. Return Value:
  2126. appropriate exchange status
  2127. Notes:
  2128. When an exchange is initiated and the start routine is invoked a number of
  2129. SMB's are sent. This routine is invoked when all processing pertaining to the
  2130. SMB's that have been sent has ceased.
  2131. This routine encapsulates all the idiosyncratic behaviour associated with the
  2132. transports.
  2133. --*/
  2134. {
  2135. SmbCeAcquireSpinLock();
  2136. ASSERT(!BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED));
  2137. if (PendingOperationMask & SMBCE_LOCAL_OPERATION) {
  2138. ASSERT(pExchange->LocalPendingOperations > 0);
  2139. pExchange->LocalPendingOperations--;
  2140. }
  2141. if (PendingOperationMask & SMBCE_SEND_COMPLETE_OPERATION) {
  2142. ASSERT(pExchange->SendCompletePendingOperations > 0);
  2143. pExchange->SendCompletePendingOperations--;
  2144. }
  2145. if (PendingOperationMask & SMBCE_COPY_DATA_OPERATION) {
  2146. ASSERT(pExchange->CopyDataPendingOperations > 0);
  2147. pExchange->CopyDataPendingOperations--;
  2148. }
  2149. if ((PendingOperationMask & SMBCE_RECEIVE_OPERATION) &&
  2150. (pExchange->ReceivePendingOperations > 0)) {
  2151. pExchange->ReceivePendingOperations--;
  2152. }
  2153. SmbCeReleaseSpinLock();
  2154. return STATUS_SUCCESS;
  2155. }
  2156. SMBCE_EXCHANGE_STATUS
  2157. SmbCeDecrementPendingOperationsAndFinalize(
  2158. PSMB_EXCHANGE pExchange,
  2159. ULONG PendingOperationMask,
  2160. PVOID FileName,
  2161. ULONG FileLine)
  2162. /*++
  2163. Routine Description:
  2164. This routine decrements the corresponding pending operation count
  2165. and finalizes an exchange instance if required
  2166. Arguments:
  2167. pExchange - the exchange to be finalized.
  2168. PendingOperationsMask -- the pending operations to be decremented.
  2169. Return Value:
  2170. appropriate exchange status
  2171. Notes:
  2172. When an exchange is initiated and the start routine is invoked a number of
  2173. SMB's are sent. This routine is invoked when all processing pertaining to the
  2174. SMB's that have been sent has ceased.
  2175. This routine encapsulates all the idiosyncratic behaviour associated with the
  2176. transports.
  2177. --*/
  2178. {
  2179. BOOLEAN fFinalizeExchange = FALSE;
  2180. SMBCE_EXCHANGE_STATUS ExchangeStatus;
  2181. SmbCeAcquireSpinLock();
  2182. ASSERT(!BooleanFlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED));
  2183. if (PendingOperationMask & SMBCE_LOCAL_OPERATION) {
  2184. ASSERT(pExchange->LocalPendingOperations > 0);
  2185. pExchange->LocalPendingOperations--;
  2186. }
  2187. if (PendingOperationMask & SMBCE_SEND_COMPLETE_OPERATION) {
  2188. ASSERT(pExchange->SendCompletePendingOperations > 0);
  2189. pExchange->SendCompletePendingOperations--;
  2190. }
  2191. if (PendingOperationMask & SMBCE_COPY_DATA_OPERATION) {
  2192. ASSERT(pExchange->CopyDataPendingOperations > 0);
  2193. pExchange->CopyDataPendingOperations--;
  2194. }
  2195. if ((PendingOperationMask & SMBCE_RECEIVE_OPERATION) &&
  2196. (pExchange->ReceivePendingOperations > 0)) {
  2197. pExchange->ReceivePendingOperations--;
  2198. }
  2199. fFinalizeExchange = SmbCeCanExchangeBeFinalized(
  2200. pExchange,
  2201. &ExchangeStatus);
  2202. SmbCeReleaseSpinLock();
  2203. if (fFinalizeExchange) {
  2204. SmbCepFinalizeExchange(pExchange);
  2205. }
  2206. return ExchangeStatus;
  2207. }
  2208. VOID
  2209. SmbCeFinalizeExchangeOnDisconnect(
  2210. PSMB_EXCHANGE pExchange)
  2211. /*++
  2212. Routine Description:
  2213. This routine handles the finalization of an exchange instance during transport disconnects
  2214. Arguments:
  2215. pExchange - the exchange instance
  2216. --*/
  2217. {
  2218. PAGED_CODE();
  2219. if (pExchange != NULL) {
  2220. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  2221. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  2222. pExchange->ReceivePendingOperations = 0;
  2223. SmbCeFinalizeExchange(pExchange);
  2224. }
  2225. }
  2226. VOID
  2227. SmbCeSetExpiryTime(
  2228. PSMB_EXCHANGE pExchange)
  2229. /*++
  2230. Routine Description:
  2231. This routine sets the expiry time for a timed exchange,
  2232. i.e., SMBCE_EXCHANGE_TIMED_OPERATION must be set
  2233. Arguments:
  2234. pExchange - the exchange instance.
  2235. Notes:
  2236. --*/
  2237. {
  2238. LARGE_INTEGER CurrentTime;
  2239. LARGE_INTEGER ExpiryTimeInTicks;
  2240. KeQueryTickCount( &CurrentTime );
  2241. ExpiryTimeInTicks.QuadPart = (1000 * 1000 * 10) / KeQueryTimeIncrement();
  2242. ExpiryTimeInTicks.QuadPart = MRxSmbConfiguration.SessionTimeoutInterval * ExpiryTimeInTicks.QuadPart;
  2243. pExchange->ExpiryTime.QuadPart = CurrentTime.QuadPart + ExpiryTimeInTicks.QuadPart;
  2244. }
  2245. BOOLEAN
  2246. SmbCeDetectExpiredExchanges(
  2247. PSMBCEDB_SERVER_ENTRY pServerEntry)
  2248. /*++
  2249. Routine Description:
  2250. This routine periodically walks the list of timed exchanges and chooses the
  2251. instances for finalization.
  2252. A timed exchange choosen by this routine will have waited for some network
  2253. response for the given time interval
  2254. Arguments:
  2255. pServerEntry -- the server entry for which this needs to be done
  2256. Notes:
  2257. --*/
  2258. {
  2259. BOOLEAN ExpiredExchangesDetected = FALSE;
  2260. PSMB_EXCHANGE pExchange;
  2261. PLIST_ENTRY pListHead;
  2262. PLIST_ENTRY pListEntry;
  2263. LARGE_INTEGER CurrentTime;
  2264. PAGED_CODE();
  2265. KeQueryTickCount( &CurrentTime );
  2266. SmbCeAcquireResource();
  2267. pListHead = &pServerEntry->ActiveExchanges;
  2268. pListEntry = pListHead->Flink;
  2269. while (pListEntry != pListHead) {
  2270. PLIST_ENTRY pNextListEntry;
  2271. pNextListEntry = pListEntry->Flink;
  2272. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  2273. // There are two kinds of exchanges that are candidates for
  2274. // time out finalization.
  2275. // (1) Any exchange which has a outstanding send complete
  2276. // operation which has not completed.
  2277. // (2) timed network operation exchanges which have a
  2278. // receive or copy data operation pending.
  2279. //
  2280. // In all such cases the associated server entry is marked
  2281. // for tear down and further processing is terminated.
  2282. //
  2283. if ((pExchange->SendCompletePendingOperations > 0) ||
  2284. (FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION) &&
  2285. ((pExchange->CopyDataPendingOperations > 0) ||
  2286. (pExchange->ReceivePendingOperations > 0)))) {
  2287. if ((pExchange->ExpiryTime.QuadPart != 0) &&
  2288. (pExchange->ExpiryTime.QuadPart < CurrentTime.QuadPart) &&
  2289. !FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED)) {
  2290. RxLog(("Marking server for tear down %lx \n",pServerEntry));
  2291. ExpiredExchangesDetected = TRUE;
  2292. break;
  2293. }
  2294. }
  2295. pListEntry = pNextListEntry;
  2296. }
  2297. SmbCeReleaseResource();
  2298. return ExpiredExchangesDetected;
  2299. }
  2300. //
  2301. // Default handler implementation of exchange handler functions.
  2302. //
  2303. NTSTATUS
  2304. DefaultSmbExchangeIndError(
  2305. IN PSMB_EXCHANGE pExchange) // the SMB exchange instance
  2306. {
  2307. PAGED_CODE();
  2308. UNREFERENCED_PARAMETER(pExchange);
  2309. return STATUS_NOT_IMPLEMENTED;
  2310. }
  2311. NTSTATUS
  2312. DefaultSmbExchangeIndReceive(
  2313. IN PSMB_EXCHANGE pExchange) // The exchange instance
  2314. {
  2315. PAGED_CODE();
  2316. UNREFERENCED_PARAMETER(pExchange);
  2317. return STATUS_NOT_IMPLEMENTED;
  2318. }
  2319. NTSTATUS
  2320. DefaultSmbExchangeIndSendCallback(
  2321. IN PSMB_EXCHANGE pExchange) // The exchange instance
  2322. {
  2323. PAGED_CODE();
  2324. UNREFERENCED_PARAMETER(pExchange);
  2325. return STATUS_NOT_IMPLEMENTED;
  2326. }
  2327.