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.

2291 lines
64 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. transport.c
  5. Abstract:
  6. This module implements all transport related functions in the SMB connection engine
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include "tdikrnl.h"
  11. NTSTATUS
  12. SmbCeIsServerAvailable(
  13. PUNICODE_STRING Name
  14. );
  15. VOID
  16. SmbCeServerIsUnavailable(
  17. PUNICODE_STRING Name,
  18. NTSTATUS Status
  19. );
  20. VOID
  21. SmbCeDiscardUnavailableServerList( );
  22. VOID
  23. MRxSmbpOverrideBindingPriority(
  24. PUNICODE_STRING pTransportName,
  25. PULONG pPriority
  26. );
  27. VOID
  28. MRxSmbPnPBindingHandler(
  29. IN TDI_PNP_OPCODE PnPOpcode,
  30. IN PUNICODE_STRING pTransportName,
  31. IN PWSTR BindingList
  32. );
  33. NTSTATUS
  34. MRxSmbPnPPowerHandler(
  35. IN PUNICODE_STRING DeviceName,
  36. IN PNET_PNP_EVENT PowerEvent,
  37. IN PTDI_PNP_CONTEXT Context1,
  38. IN PTDI_PNP_CONTEXT Context2
  39. );
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text(PAGE, SmbCeFindTransport)
  42. #pragma alloc_text(PAGE, SmbCepInitializeServerTransport)
  43. #pragma alloc_text(PAGE, SmbCeInitializeExchangeTransport)
  44. #pragma alloc_text(PAGE, SmbCeUninitializeExchangeTransport)
  45. #pragma alloc_text(PAGE, SmbCepDereferenceTransport)
  46. #pragma alloc_text(PAGE, MRxSmbpBindTransportCallback)
  47. #pragma alloc_text(PAGE, MRxSmbpBindTransportWorkerThreadRoutine)
  48. #pragma alloc_text(PAGE, MRxSmbpUnbindTransportCallback)
  49. #pragma alloc_text(PAGE, MRxSmbpOverrideBindingPriority)
  50. #pragma alloc_text(PAGE, MRxSmbPnPBindingHandler)
  51. #pragma alloc_text(PAGE, MRxSmbRegisterForPnpNotifications)
  52. #pragma alloc_text(PAGE, MRxSmbDeregisterForPnpNotifications)
  53. #pragma alloc_text(PAGE, SmbCeDereferenceTransportArray)
  54. #pragma alloc_text(PAGE, SmbCeIsServerAvailable)
  55. #pragma alloc_text(PAGE, SmbCeServerIsUnavailable)
  56. #pragma alloc_text(PAGE, SmbCeDiscardUnavailableServerList)
  57. #endif
  58. SMBCE_TRANSPORTS MRxSmbTransports;
  59. //
  60. // The head of the list of servers that are currently unavailable
  61. //
  62. LIST_ENTRY UnavailableServerList = { &UnavailableServerList, &UnavailableServerList };
  63. //
  64. // Each entry in the UnavailableServerList is one of these:
  65. //
  66. typedef struct {
  67. LIST_ENTRY ListEntry;
  68. UNICODE_STRING Name; // Name of server that is unavailable
  69. NTSTATUS Status; // Status received when we tried to connect to it
  70. LARGE_INTEGER Time; // Time when we last attempted to connect
  71. } *PUNAVAILABLE_SERVER;
  72. //
  73. // Protects UnavailableServerList
  74. //
  75. ERESOURCE UnavailableServerListResource = {0};
  76. //
  77. // Time (seconds) that we keep an entry in the UnavailableServerList.
  78. // We will not retry a connection attempt to a server
  79. // for UNAVAILABLE_SERVER_TIME seconds
  80. //
  81. #define UNAVAILABLE_SERVER_TIME 10
  82. RXDT_DefineCategory(TRANSPRT);
  83. #define Dbg (DEBUG_TRACE_TRANSPRT)
  84. NTSTATUS
  85. MRxSmbInitializeTransport()
  86. /*++
  87. Routine Description:
  88. This routine initializes the transport related data structures
  89. Returns:
  90. STATUS_SUCCESS if the transport data structures was successfully initialized
  91. Notes:
  92. --*/
  93. {
  94. KeInitializeSpinLock(&MRxSmbTransports.Lock);
  95. MRxSmbTransports.pTransportArray = NULL;
  96. ExInitializeResource( &UnavailableServerListResource );
  97. return STATUS_SUCCESS;
  98. }
  99. NTSTATUS
  100. MRxSmbUninitializeTransport()
  101. /*++
  102. Routine Description:
  103. This routine uninitializes the transport related data structures
  104. Notes:
  105. --*/
  106. {
  107. PSMBCE_TRANSPORT pTransport;
  108. KIRQL SavedIrql;
  109. ULONG TransportCount = 0;
  110. PSMBCE_TRANSPORT_ARRAY pTransportArray = NULL;
  111. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  112. if (MRxSmbTransports.pTransportArray != NULL) {
  113. pTransportArray = MRxSmbTransports.pTransportArray;
  114. MRxSmbTransports.pTransportArray = NULL;
  115. }
  116. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  117. if (pTransportArray != NULL) {
  118. SmbCeDereferenceTransportArray(pTransportArray);
  119. }
  120. SmbCeDiscardUnavailableServerList();
  121. ExDeleteResource( &UnavailableServerListResource );
  122. return STATUS_SUCCESS;
  123. }
  124. NTSTATUS
  125. SmbCeAddTransport(
  126. PSMBCE_TRANSPORT pNewTransport)
  127. /*++
  128. Routine Description:
  129. This routine adds a new instance to the known list of transports
  130. Parameters:
  131. pNewTransport -- the transport instance to be added
  132. Notes:
  133. --*/
  134. {
  135. NTSTATUS Status = STATUS_SUCCESS;
  136. KIRQL SavedIrql;
  137. LONG Count;
  138. PSMBCE_TRANSPORT_ARRAY pNewTransportArray = NULL;
  139. PSMBCE_TRANSPORT_ARRAY pOldTransportArray;
  140. PSMBCE_TRANSPORT *pTransports = NULL;
  141. PRXCE_ADDRESS *LocalAddresses = NULL;
  142. SmbCeAcquireResource();
  143. pOldTransportArray = SmbCeReferenceTransportArray();
  144. if (pOldTransportArray != NULL)
  145. Count = pOldTransportArray->Count + 1;
  146. else
  147. Count = 1;
  148. pNewTransportArray = (PSMBCE_TRANSPORT_ARRAY)RxAllocatePoolWithTag(
  149. NonPagedPool,
  150. sizeof(SMBCE_TRANSPORT_ARRAY),
  151. MRXSMB_TRANSPORT_POOLTAG);
  152. if (pNewTransportArray == NULL) {
  153. Status = STATUS_INSUFFICIENT_RESOURCES;
  154. }
  155. if (Status == STATUS_SUCCESS) {
  156. pTransports = (PSMBCE_TRANSPORT *)RxAllocatePoolWithTag(
  157. NonPagedPool,
  158. Count * sizeof(PSMBCE_TRANSPORT),
  159. MRXSMB_TRANSPORT_POOLTAG);
  160. if (pTransports == NULL) {
  161. Status = STATUS_INSUFFICIENT_RESOURCES;
  162. }
  163. }
  164. if (Status == STATUS_SUCCESS) {
  165. LocalAddresses = (PRXCE_ADDRESS *)RxAllocatePoolWithTag(
  166. NonPagedPool,
  167. Count * sizeof(PRXCE_ADDRESS),
  168. MRXSMB_TRANSPORT_POOLTAG);
  169. if (LocalAddresses == NULL) {
  170. Status = STATUS_INSUFFICIENT_RESOURCES;
  171. }
  172. }
  173. if (Status == STATUS_SUCCESS) {
  174. LONG i;
  175. if (Count > 1) {
  176. PSMBCE_TRANSPORT *pOldTransports;
  177. pOldTransports = pOldTransportArray->SmbCeTransports;
  178. for (i=0;i<Count-1;i++) {
  179. if (pNewTransport->Priority < pOldTransports[i]->Priority) { // The lower number, the higher priority
  180. break;
  181. }
  182. pTransports[i] = pOldTransports[i];
  183. LocalAddresses[i] = &pOldTransports[i]->RxCeAddress;
  184. }
  185. pTransports[i] = pNewTransport;
  186. LocalAddresses[i] = &pNewTransport->RxCeAddress;
  187. for (;i<Count-1;i++) {
  188. pTransports[i+1] = pOldTransports[i];
  189. LocalAddresses[i+1] = &pOldTransports[i]->RxCeAddress;
  190. }
  191. } else {
  192. pTransports[0] = pNewTransport;
  193. LocalAddresses[0] = &pNewTransport->RxCeAddress;
  194. }
  195. for(i=0;i<Count;i++)
  196. SmbCeReferenceTransport(pTransports[i]);
  197. pNewTransportArray->ReferenceCount = 1;
  198. pNewTransportArray->Count = Count;
  199. pNewTransportArray->SmbCeTransports = &pTransports[0];
  200. pNewTransportArray->LocalAddresses = &LocalAddresses[0];
  201. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  202. MRxSmbTransports.pTransportArray = pNewTransportArray;
  203. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  204. // Double dereferencing is necessary to ensure that
  205. // the old transport array is destroyed.
  206. SmbCeDereferenceTransportArray(pOldTransportArray);
  207. }
  208. SmbCeDereferenceTransportArray(pOldTransportArray);
  209. SmbCeReleaseResource();
  210. if (Status != STATUS_SUCCESS) {
  211. if (pNewTransportArray != NULL) {
  212. RxFreePool(pNewTransportArray);
  213. }
  214. if (pTransports != NULL) {
  215. RxFreePool(pTransports);
  216. }
  217. if (LocalAddresses != NULL) {
  218. RxFreePool(LocalAddresses);
  219. }
  220. }
  221. SmbCeDiscardUnavailableServerList();
  222. return Status;
  223. }
  224. NTSTATUS
  225. SmbCeRemoveTransport(
  226. PSMBCE_TRANSPORT pTransport)
  227. /*++
  228. Routine Description:
  229. This routine removes a transport from the list of known transports
  230. Parameters:
  231. pTransport - the transport instance to be removed.
  232. Notes:
  233. --*/
  234. {
  235. NTSTATUS Status = STATUS_SUCCESS;
  236. KIRQL SavedIrql;
  237. LONG Count;
  238. PSMBCE_TRANSPORT_ARRAY pTransportArray = NULL;
  239. PSMBCE_TRANSPORT_ARRAY pOldTransportArray = NULL;
  240. PSMBCE_TRANSPORT *pTransports = NULL;
  241. PRXCE_ADDRESS *pLocalAddresses = NULL;
  242. SmbCeAcquireResource();
  243. pOldTransportArray = SmbCeReferenceTransportArray();
  244. if (pOldTransportArray != NULL) {
  245. LONG Index;
  246. BOOLEAN Found = FALSE;
  247. PSMBCE_TRANSPORT *pOldTransports;
  248. // Establish the fact that the given transport is part of the array.
  249. // if it is not then no further action is necessary
  250. pOldTransports = pOldTransportArray->SmbCeTransports;
  251. for (Index = 0; Index < (LONG)pOldTransportArray->Count; Index++) {
  252. if (pTransport == pOldTransports[Index]) {
  253. Found = TRUE;
  254. }
  255. }
  256. if (Found) {
  257. Count = pOldTransportArray->Count - 1;
  258. if (Count > 0) {
  259. pTransportArray = (PSMBCE_TRANSPORT_ARRAY)RxAllocatePoolWithTag(
  260. NonPagedPool,
  261. sizeof(SMBCE_TRANSPORT_ARRAY),
  262. MRXSMB_TRANSPORT_POOLTAG);
  263. if (pTransportArray == NULL) {
  264. Status = STATUS_INSUFFICIENT_RESOURCES;
  265. }
  266. if (Status == STATUS_SUCCESS) {
  267. pTransports = (PSMBCE_TRANSPORT *)RxAllocatePoolWithTag(
  268. NonPagedPool,
  269. Count * sizeof(PSMBCE_TRANSPORT),
  270. MRXSMB_TRANSPORT_POOLTAG);
  271. if (pTransports == NULL) {
  272. Status = STATUS_INSUFFICIENT_RESOURCES;
  273. }
  274. }
  275. if (Status == STATUS_SUCCESS) {
  276. pLocalAddresses = (PRXCE_ADDRESS *)RxAllocatePoolWithTag(
  277. NonPagedPool,
  278. Count * sizeof(PRXCE_ADDRESS),
  279. MRXSMB_TRANSPORT_POOLTAG);
  280. if (pLocalAddresses == NULL) {
  281. Status = STATUS_INSUFFICIENT_RESOURCES;
  282. }
  283. }
  284. if (Status == STATUS_SUCCESS) {
  285. LONG i, j;
  286. for (i=0, j=0;i<Count+1;i++) {
  287. if (pTransport != pOldTransports[i]) {
  288. pTransports[j] = pOldTransports[i];
  289. pLocalAddresses[j] = &pOldTransports[i]->RxCeAddress;
  290. j++;
  291. }
  292. }
  293. for(i=0;i<Count;i++)
  294. SmbCeReferenceTransport(pTransports[i]);
  295. pTransportArray->ReferenceCount = 1;
  296. pTransportArray->Count = Count;
  297. pTransportArray->SmbCeTransports = &pTransports[0];
  298. pTransportArray->LocalAddresses = &pLocalAddresses[0];
  299. }
  300. }
  301. if (Status == STATUS_SUCCESS) {
  302. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  303. MRxSmbTransports.pTransportArray = pTransportArray;
  304. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  305. // Double dereferencing is necessary to ensure that
  306. // the old transport array is destroyed.
  307. SmbCeDereferenceTransportArray(pOldTransportArray);
  308. } else {
  309. if (pTransportArray != NULL) {
  310. RxFreePool(pTransportArray);
  311. }
  312. if (pTransports != NULL) {
  313. RxFreePool(pTransports);
  314. }
  315. if (pLocalAddresses != NULL) {
  316. RxFreePool(pLocalAddresses);
  317. }
  318. }
  319. }
  320. SmbCeDereferenceTransportArray(pOldTransportArray);
  321. }
  322. SmbCeReleaseResource();
  323. SmbCeDiscardUnavailableServerList();
  324. return Status;
  325. }
  326. PSMBCE_TRANSPORT
  327. SmbCeFindTransport(
  328. PUNICODE_STRING pTransportName)
  329. /*++
  330. Routine Description:
  331. This routine maps a transport name to the appropriate
  332. PSMBCE_TRANSPORT instance
  333. Arguments:
  334. pTransportName - the transport name
  335. Return Value:
  336. a valid PSMBCE_TRANSPORT if one exists otherwise NULL
  337. Notes:
  338. --*/
  339. {
  340. KIRQL SavedIrql;
  341. PLIST_ENTRY pEntry;
  342. PSMBCE_TRANSPORT pTransport;
  343. BOOLEAN Found = FALSE;
  344. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  345. PAGED_CODE();
  346. pTransportArray = SmbCeReferenceTransportArray();
  347. if (pTransportArray == NULL) {
  348. RxDbgTrace(0, Dbg, ("SmbCeFindTransport : Transport not available.\n"));
  349. return NULL;
  350. }
  351. if (pTransportArray != NULL) {
  352. ULONG i;
  353. for (i=0;i<pTransportArray->Count;i++) {
  354. pTransport = pTransportArray->SmbCeTransports[i];
  355. if (RtlEqualUnicodeString(
  356. &pTransport->RxCeTransport.Name,
  357. pTransportName,
  358. TRUE)) {
  359. SmbCeReferenceTransport(pTransport);
  360. Found = TRUE;
  361. break;
  362. }
  363. }
  364. }
  365. if (!Found) {
  366. pTransport = NULL;
  367. }
  368. SmbCeDereferenceTransportArray(pTransportArray);
  369. return pTransport;
  370. }
  371. VOID
  372. SmbCepTearDownServerTransport(
  373. PSMBCEDB_SERVER_ENTRY pServerEntry)
  374. /*++
  375. Routine Description:
  376. This routine uninitializes the transport information corresponding to a server
  377. Arguments:
  378. pServerEntry - the server entry instance in the database
  379. Notes:
  380. --*/
  381. {
  382. NTSTATUS Status = STATUS_SUCCESS;
  383. SMBCEDB_SERVER_TYPE ServerType = SmbCeGetServerType(pServerEntry);
  384. BOOLEAN WaitForTransportRundown = FALSE;
  385. BOOLEAN TearDown = FALSE;
  386. SmbCeAcquireSpinLock();
  387. if (!pServerEntry->IsTransportDereferenced) {
  388. // ServerEntry takes only one reference count of transport, which should only be
  389. // dereferenced once when it comes to tear down transport. Multiple dereference called
  390. // from construct server transport and PNP unbind transport needs to be prevented.
  391. pServerEntry->IsTransportDereferenced = TRUE;
  392. TearDown = TRUE;
  393. KeInitializeEvent(&pServerEntry->TransportRundownEvent,NotificationEvent,FALSE);
  394. if (pServerEntry->pTransport != NULL) {
  395. pServerEntry->pTransport->State = SMBCEDB_MARKED_FOR_DELETION;
  396. pServerEntry->pTransport->pRundownEvent = &pServerEntry->TransportRundownEvent;
  397. WaitForTransportRundown = TRUE;
  398. }
  399. } else {
  400. if (pServerEntry->pTransport != NULL) {
  401. WaitForTransportRundown = TRUE;
  402. }
  403. }
  404. SmbCeReleaseSpinLock();
  405. if (TearDown) {
  406. if (pServerEntry->pTransport != NULL) {
  407. SmbCeDereferenceServerTransport(&pServerEntry->pTransport);
  408. }
  409. }
  410. if (WaitForTransportRundown) {
  411. KeWaitForSingleObject(
  412. &pServerEntry->TransportRundownEvent,
  413. Executive,
  414. KernelMode,
  415. FALSE,
  416. NULL );
  417. }
  418. }
  419. VOID
  420. SmbCeTearDownServerTransport(
  421. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  422. /*++
  423. Routine Description:
  424. This routine tears down the server transport instance
  425. Arguments:
  426. pContext - the server transport construction context
  427. Notes:
  428. --*/
  429. {
  430. SmbCepTearDownServerTransport(pContext->pServerEntry);
  431. if (pContext->pCompletionEvent != NULL) {
  432. ASSERT(pContext->pCallbackContext == NULL);
  433. ASSERT(pContext->pCompletionRoutine == NULL);
  434. KeSetEvent(
  435. pContext->pCompletionEvent,
  436. 0,
  437. FALSE );
  438. } else if (pContext->pCallbackContext != NULL) {
  439. ASSERT(pContext->pCompletionEvent == NULL);
  440. (pContext->pCompletionRoutine)(pContext->pCallbackContext);
  441. }
  442. RxFreePool(pContext);
  443. }
  444. VOID
  445. SmbCepUpdateTransportConstructionState(
  446. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  447. {
  448. SMBCE_SERVER_TRANSPORT_CONSTRUCTION_STATE State;
  449. if (pContext->Status == STATUS_SUCCESS) {
  450. if (pContext->TransportsToBeConstructed & SMBCE_STT_VC) {
  451. pContext->TransportsToBeConstructed &= ~SMBCE_STT_VC;
  452. State = SmbCeServerVcTransportConstructionBegin;
  453. } else {
  454. State = SmbCeServerTransportConstructionEnd;
  455. }
  456. } else {
  457. State = SmbCeServerTransportConstructionEnd;
  458. }
  459. pContext->State = State;
  460. }
  461. VOID
  462. SmbCeConstructServerTransport(
  463. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  464. /*++
  465. Routine Description:
  466. This routine constructs the server transport instance
  467. Arguments:
  468. pContext - the server transport construction context
  469. Notes:
  470. --*/
  471. {
  472. NTSTATUS Status;
  473. PSMBCEDB_SERVER_ENTRY pServerEntry;
  474. SMBCEDB_SERVER_TYPE ServerType;
  475. BOOLEAN ContinueConstruction = TRUE;
  476. BOOLEAN UpdateUnavailableServerlist = TRUE;
  477. PAGED_CODE();
  478. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  479. pServerEntry = pContext->pServerEntry;
  480. ServerType = SmbCeGetServerType(pServerEntry);
  481. do {
  482. switch (pContext->State) {
  483. case SmbCeServerTransportConstructionBegin :
  484. {
  485. if (pServerEntry->pTransport != NULL) {
  486. SmbCepTearDownServerTransport(pServerEntry);
  487. }
  488. ASSERT(pServerEntry->pTransport == NULL);
  489. pContext->Status = STATUS_SUCCESS;
  490. // See if we have any reason to believe this server is unavailable
  491. pContext->Status = SmbCeIsServerAvailable( &pServerEntry->Name );
  492. if (pContext->Status != STATUS_SUCCESS) {
  493. UpdateUnavailableServerlist = FALSE;
  494. }
  495. SmbCepUpdateTransportConstructionState(pContext);
  496. }
  497. break;
  498. case SmbCeServerVcTransportConstructionBegin:
  499. {
  500. Status = VctInstantiateServerTransport(
  501. pContext);
  502. if (Status == STATUS_PENDING) {
  503. ContinueConstruction = FALSE;
  504. break;
  505. }
  506. ASSERT(pContext->State == SmbCeServerVcTransportConstructionEnd);
  507. }
  508. // lack of break intentional
  509. case SmbCeServerVcTransportConstructionEnd:
  510. {
  511. SmbCepUpdateTransportConstructionState(pContext);
  512. }
  513. break;
  514. case SmbCeServerTransportConstructionEnd:
  515. {
  516. pServerEntry->ServerStatus = pContext->Status;
  517. if (pServerEntry->ServerStatus == STATUS_SUCCESS) {
  518. SmbCeAcquireSpinLock();
  519. if (pContext->pTransport != NULL) {
  520. pContext->pTransport->SwizzleCount = 1;
  521. }
  522. pServerEntry->pTransport = pContext->pTransport;
  523. pContext->pTransport = NULL;
  524. if (pContext->pCallbackContext != NULL) {
  525. pContext->pCallbackContext->Status = STATUS_SUCCESS;
  526. }
  527. pServerEntry->IsTransportDereferenced = FALSE;
  528. SmbCeReleaseSpinLock();
  529. } else {
  530. PRX_CONTEXT pRxContext = NULL;
  531. if (UpdateUnavailableServerlist) {
  532. SmbCeServerIsUnavailable( &pServerEntry->Name, pServerEntry->ServerStatus );
  533. }
  534. if (pContext->pTransport != NULL) {
  535. pContext->pTransport->pDispatchVector->TearDown(
  536. pContext->pTransport);
  537. }
  538. pContext->pTransport = NULL;
  539. pServerEntry->pTransport = NULL;
  540. if ((pContext->pCallbackContext) &&
  541. (pContext->pCallbackContext->SrvCalldownStructure)) {
  542. pRxContext =
  543. pContext->pCallbackContext->SrvCalldownStructure->RxContext;
  544. }
  545. if (pContext->pCallbackContext != NULL) {
  546. pContext->pCallbackContext->Status = pServerEntry->ServerStatus;
  547. }
  548. }
  549. if (pContext->pCompletionEvent != NULL) {
  550. ASSERT(pContext->pCallbackContext == NULL);
  551. ASSERT(pContext->pCompletionRoutine == NULL);
  552. KeSetEvent(
  553. pContext->pCompletionEvent,
  554. 0,
  555. FALSE );
  556. } else if (pContext->pCallbackContext != NULL) {
  557. ASSERT(pContext->pCompletionEvent == NULL);
  558. (pContext->pCompletionRoutine)(pContext->pCallbackContext);
  559. } else {
  560. ASSERT(!"ill formed transport initialization context");
  561. }
  562. // pServerEntry->ConstructionContext = NULL;
  563. RxFreePool(pContext);
  564. ContinueConstruction = FALSE;
  565. }
  566. }
  567. } while (ContinueConstruction);
  568. }
  569. NTSTATUS
  570. SmbCepInitializeServerTransport(
  571. PSMBCEDB_SERVER_ENTRY pServerEntry,
  572. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CALLBACK pCallbackRoutine,
  573. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext,
  574. ULONG TransportsToBeConstructed)
  575. /*++
  576. Routine Description:
  577. This routine initializes the transport information corresponding to a server
  578. Arguments:
  579. pServerEntry - the server entry instance in the database
  580. pCallbackRoutine - the callback routine
  581. pCallbackContext - the callback context
  582. TransportsToBeConstructed -- the transports to be constructed
  583. Return Value:
  584. STATUS_SUCCESS - the server transport construction has been finalized.
  585. Other Status codes correspond to error situations.
  586. Notes:
  587. Currently, only connection oriented transports are handled.
  588. --*/
  589. {
  590. NTSTATUS Status;
  591. BOOLEAN CompleteConstruction;
  592. PAGED_CODE();
  593. if ((pServerEntry->ServerStatus == STATUS_SUCCESS) &&
  594. (pServerEntry->pTransport != NULL)) {
  595. Status = STATUS_SUCCESS;
  596. CompleteConstruction = TRUE;
  597. } else {
  598. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext;
  599. pContext = RxAllocatePoolWithTag(
  600. NonPagedPool,
  601. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT),
  602. MRXSMB_TRANSPORT_POOLTAG);
  603. CompleteConstruction = (pContext == NULL);
  604. if (pContext != NULL) {
  605. KEVENT CompletionEvent;
  606. RtlZeroMemory(
  607. pContext,
  608. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT));
  609. pContext->Status = STATUS_SUCCESS;
  610. pContext->pServerEntry = pServerEntry;
  611. pContext->State = SmbCeServerTransportConstructionBegin;
  612. pContext->TransportsToBeConstructed = TransportsToBeConstructed;
  613. if (pCallbackContext == NULL) {
  614. KeInitializeEvent(
  615. &CompletionEvent,
  616. NotificationEvent,
  617. FALSE);
  618. pContext->pCompletionEvent = &CompletionEvent;
  619. } else {
  620. pContext->pCallbackContext = pCallbackContext;
  621. pContext->pCompletionRoutine = pCallbackRoutine;
  622. }
  623. pServerEntry->ConstructionContext = (PVOID)pContext;
  624. Status = STATUS_PENDING;
  625. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  626. SmbCeConstructServerTransport(pContext);
  627. } else {
  628. Status = RxPostToWorkerThread(
  629. MRxSmbDeviceObject,
  630. CriticalWorkQueue,
  631. &pContext->WorkQueueItem,
  632. SmbCeConstructServerTransport,
  633. pContext);
  634. if (Status == STATUS_SUCCESS) {
  635. Status = STATUS_PENDING;
  636. } else {
  637. pServerEntry->ConstructionContext = NULL;
  638. RxFreePool(pContext);
  639. CompleteConstruction = TRUE;
  640. }
  641. }
  642. if ((Status == STATUS_PENDING) && (pCallbackContext == NULL)) {
  643. KeWaitForSingleObject(
  644. &CompletionEvent,
  645. Executive,
  646. KernelMode,
  647. FALSE,
  648. NULL );
  649. Status = pServerEntry->ServerStatus;
  650. }
  651. } else {
  652. Status = STATUS_INSUFFICIENT_RESOURCES;
  653. }
  654. }
  655. if (CompleteConstruction) {
  656. pServerEntry->ServerStatus = Status;
  657. if (pCallbackRoutine != NULL && pCallbackContext != NULL) {
  658. pCallbackContext->Status = Status;
  659. (pCallbackRoutine)(pCallbackContext);
  660. Status = STATUS_PENDING;
  661. }
  662. }
  663. return Status;
  664. }
  665. NTSTATUS
  666. SmbCeUninitializeServerTransport(
  667. PSMBCEDB_SERVER_ENTRY pServerEntry,
  668. PSMBCE_SERVER_TRANSPORT_DESTRUCTION_CALLBACK pCallbackRoutine,
  669. PVOID pCallbackContext)
  670. /*++
  671. Routine Description:
  672. This routine uninitializes the transport information corresponding to a server
  673. Arguments:
  674. pServerEntry - the server entry instance in the database
  675. Returns:
  676. STATUS_SUCCESS if successful
  677. Notes:
  678. Currently, only connection oriented transports are handled.
  679. In order to handle async. operations the uninitialization has to be coordinated
  680. with the referencing mechanism. It is for this reason that this routine sets up
  681. a rundown event and waits for it to be set.
  682. --*/
  683. {
  684. NTSTATUS Status = STATUS_SUCCESS;
  685. PAGED_CODE();
  686. if (pCallbackRoutine == NULL &&
  687. IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  688. SmbCepTearDownServerTransport(pServerEntry);
  689. } else {
  690. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext;
  691. pContext = RxAllocatePoolWithTag(
  692. NonPagedPool,
  693. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT),
  694. MRXSMB_TRANSPORT_POOLTAG);
  695. if (pContext != NULL) {
  696. KEVENT CompletionEvent;
  697. RtlZeroMemory(
  698. pContext,
  699. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT));
  700. pContext->Status = STATUS_SUCCESS;
  701. pContext->pServerEntry = pServerEntry;
  702. if (pCallbackRoutine == NULL) {
  703. KeInitializeEvent(
  704. &CompletionEvent,
  705. NotificationEvent,
  706. FALSE);
  707. pContext->pCompletionEvent = &CompletionEvent;
  708. } else {
  709. pContext->pCallbackContext = pCallbackContext;
  710. pContext->pCompletionRoutine = pCallbackRoutine;
  711. }
  712. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  713. SmbCeTearDownServerTransport(pContext);
  714. } else {
  715. Status = RxPostToWorkerThread(
  716. MRxSmbDeviceObject,
  717. CriticalWorkQueue,
  718. &pContext->WorkQueueItem,
  719. SmbCeTearDownServerTransport,
  720. pContext);
  721. }
  722. if (Status == STATUS_SUCCESS) {
  723. if (pCallbackRoutine == NULL) {
  724. KeWaitForSingleObject(
  725. &CompletionEvent,
  726. Executive,
  727. KernelMode,
  728. FALSE,
  729. NULL );
  730. } else {
  731. Status = STATUS_PENDING;
  732. }
  733. } else {
  734. RxFreePool(pContext);
  735. }
  736. } else {
  737. Status = STATUS_INSUFFICIENT_RESOURCES;
  738. }
  739. }
  740. return Status;
  741. }
  742. VOID
  743. SmbCeCompleteUninitializeServerTransport(
  744. PSMBCEDB_SERVER_ENTRY pServerEntry)
  745. {
  746. // in case of async uninitialize server transport, an additional reference count of
  747. // server entry should be taken so that uninitialize server transport will not be
  748. // called once again from tear down server entry if its reference count comes to 0
  749. // before uninitialize server transport is done.
  750. SmbCeDereferenceServerEntry(pServerEntry);
  751. }
  752. NTSTATUS
  753. SmbCeInitiateDisconnect(
  754. PSMBCEDB_SERVER_ENTRY pServerEntry)
  755. /*++
  756. Routine Description:
  757. This routine initiates the TDI disconnect
  758. Arguments:
  759. pServerEntry - the server entry instance in the database
  760. Return Value:
  761. STATUS_SUCCESS - the server transport construction has been finalized.
  762. Other Status codes correspond to error situations.
  763. Notes:
  764. --*/
  765. {
  766. NTSTATUS Status;
  767. PSMBCE_SERVER_TRANSPORT pTransport;
  768. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  769. Status = SmbCeReferenceServerTransport(&pServerEntry->pTransport);
  770. if (Status == STATUS_SUCCESS) {
  771. Status = (pServerEntry->pTransport->pDispatchVector->InitiateDisconnect)(
  772. pServerEntry->pTransport);
  773. if (Status != STATUS_SUCCESS) {
  774. RxDbgTrace(0, Dbg, ("SmbCeInitiateDisconnect : Status %lx\n",Status));
  775. }
  776. SmbCeDereferenceServerTransport(&pServerEntry->pTransport);
  777. }
  778. return STATUS_SUCCESS;
  779. }
  780. LONG Initializes[SENTINEL_EXCHANGE] = {0,0,0,0};
  781. LONG Uninitializes[SENTINEL_EXCHANGE] = {0,0,0,0};
  782. NTSTATUS
  783. SmbCeInitializeExchangeTransport(
  784. PSMB_EXCHANGE pExchange)
  785. /*++
  786. Routine Description:
  787. This routine initializes the transport associated with the exchange
  788. Arguments:
  789. pExchange - the exchange to be initialized
  790. Return Value:
  791. STATUS_SUCCESS - the exchange transport initialization has been finalized.
  792. Other Status codes correspond to error situations.
  793. Notes:
  794. --*/
  795. {
  796. NTSTATUS Status;
  797. PSMBCEDB_SERVER_ENTRY pServerEntry;
  798. PAGED_CODE();
  799. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  800. Status = pExchange->SmbStatus;
  801. if (Status == STATUS_SUCCESS) {
  802. PSMBCE_SERVER_TRANSPORT *pTransportPointer;
  803. pTransportPointer = &pServerEntry->pTransport;
  804. if (*pTransportPointer != NULL) {
  805. Status = SmbCeReferenceServerTransport(pTransportPointer);
  806. if (Status == STATUS_SUCCESS) {
  807. Status = ((*pTransportPointer)->pDispatchVector->InitializeExchange)(
  808. *pTransportPointer,
  809. pExchange);
  810. if (Status == STATUS_SUCCESS) {
  811. ULONG TransportInitialized;
  812. InterlockedIncrement(&Initializes[pExchange->Type]);
  813. TransportInitialized = InterlockedExchange(&pExchange->ExchangeTransportInitialized,1);
  814. ASSERT(TransportInitialized == 0);
  815. } else {
  816. SmbCeDereferenceServerTransport(pTransportPointer);
  817. }
  818. }
  819. } else {
  820. Status = STATUS_CONNECTION_DISCONNECTED;
  821. }
  822. }
  823. return Status;
  824. }
  825. NTSTATUS
  826. SmbCeUninitializeExchangeTransport(
  827. PSMB_EXCHANGE pExchange)
  828. /*++
  829. Routine Description:
  830. This routine uniinitializes the transport associated with the exchange
  831. Arguments:
  832. pExchange - the exchange to be initialized
  833. Return Value:
  834. STATUS_SUCCESS - the exchange transport initialization has been finalized.
  835. Other Status codes correspond to error situations.
  836. Notes:
  837. --*/
  838. {
  839. NTSTATUS Status;
  840. PSMBCEDB_SERVER_ENTRY pServerEntry;
  841. PAGED_CODE();
  842. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  843. if (InterlockedExchange(&pExchange->ExchangeTransportInitialized,0)==1) {
  844. PSMBCE_SERVER_TRANSPORT *pTransportPointer;
  845. pTransportPointer = &pServerEntry->pTransport;
  846. if (*pTransportPointer != NULL) {
  847. Status = ((*pTransportPointer)->pDispatchVector->UninitializeExchange)(
  848. *pTransportPointer,
  849. pExchange);
  850. SmbCeDereferenceServerTransport(pTransportPointer);
  851. InterlockedIncrement(&Uninitializes[pExchange->Type]);
  852. return Status;
  853. } else {
  854. return STATUS_CONNECTION_DISCONNECTED;
  855. }
  856. } else {
  857. return pExchange->SmbStatus;
  858. }
  859. }
  860. NTSTATUS
  861. SmbCepReferenceServerTransport(
  862. PSMBCE_SERVER_TRANSPORT *pServerTransportPointer)
  863. /*++
  864. Routine Description:
  865. This routine references the transport associated with a server entry
  866. Arguments:
  867. pServerEntry - the server entry instance in the database
  868. Return Value:
  869. STATUS_SUCCESS - the server transport was successfully referenced
  870. Other Status codes correspond to error situations.
  871. Notes:
  872. --*/
  873. {
  874. NTSTATUS Status = STATUS_SUCCESS;
  875. SmbCeAcquireSpinLock();
  876. if (*pServerTransportPointer != NULL &&
  877. (*pServerTransportPointer)->State == SMBCEDB_ACTIVE) {
  878. InterlockedIncrement(&(*pServerTransportPointer)->SwizzleCount);
  879. Status = STATUS_SUCCESS;
  880. } else {
  881. Status = STATUS_CONNECTION_DISCONNECTED;
  882. }
  883. SmbCeReleaseSpinLock();
  884. return Status;
  885. }
  886. NTSTATUS
  887. SmbCepDereferenceServerTransport(
  888. PSMBCE_SERVER_TRANSPORT *pServerTransportPointer)
  889. /*++
  890. Routine Description:
  891. This routine dereferences the transport associated with a server entry
  892. Arguments:
  893. pServerTransportPointer - the server entry transport instance pointer
  894. Return Value:
  895. STATUS_SUCCESS - the server transport was successfully dereferenced
  896. Other Status codes correspond to error situations.
  897. Notes:
  898. On finalization this routine sets the event to enable the process awaiting
  899. tear down to restart. It also tears down the associated server transport
  900. instance.
  901. As a side effect the pointer value is set to NULL under the protection of a
  902. spin lock.
  903. --*/
  904. {
  905. NTSTATUS Status = STATUS_SUCCESS;
  906. SmbCeAcquireSpinLock();
  907. if (*pServerTransportPointer != NULL) {
  908. LONG FinalRefCount;
  909. PKEVENT pRundownEvent;
  910. PSMBCE_SERVER_TRANSPORT pServerTransport;
  911. pServerTransport = *pServerTransportPointer;
  912. FinalRefCount = InterlockedDecrement(&pServerTransport->SwizzleCount);
  913. if (FinalRefCount == 0) {
  914. pServerTransport->State = SMBCEDB_INVALID;
  915. // transport is set to NULL before the spinlock is release so that no
  916. // exchange should reference it after it's been torn down
  917. *pServerTransportPointer = NULL;
  918. pRundownEvent = pServerTransport->pRundownEvent;
  919. }
  920. SmbCeReleaseSpinLock();
  921. if (FinalRefCount == 0) {
  922. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  923. pServerTransport->pDispatchVector->TearDown(pServerTransport);
  924. } else {
  925. Status = RxDispatchToWorkerThread(
  926. MRxSmbDeviceObject,
  927. CriticalWorkQueue,
  928. pServerTransport->pDispatchVector->TearDown,
  929. pServerTransport);
  930. }
  931. }
  932. } else {
  933. SmbCeReleaseSpinLock();
  934. Status = STATUS_CONNECTION_DISCONNECTED;
  935. }
  936. return Status;
  937. }
  938. NTSTATUS
  939. SmbCepReferenceTransport(
  940. PSMBCE_TRANSPORT pTransport)
  941. /*++
  942. Routine Description:
  943. This routine references the transport instance
  944. Arguments:
  945. pTransport - the transport instance
  946. Return Value:
  947. STATUS_SUCCESS - the server transport was successfully referenced
  948. Other Status codes correspond to error situations.
  949. Notes:
  950. --*/
  951. {
  952. NTSTATUS Status = STATUS_SUCCESS;
  953. if (pTransport != NULL) {
  954. SmbCeAcquireSpinLock();
  955. if (pTransport->Active) {
  956. InterlockedIncrement(&pTransport->SwizzleCount);
  957. Status = STATUS_SUCCESS;
  958. } else {
  959. Status = STATUS_UNSUCCESSFUL;
  960. }
  961. SmbCeReleaseSpinLock();
  962. } else {
  963. Status = STATUS_INVALID_PARAMETER;
  964. }
  965. return Status;
  966. }
  967. NTSTATUS
  968. SmbCepDereferenceTransport(
  969. PSMBCE_TRANSPORT pTransport)
  970. /*++
  971. Routine Description:
  972. This routine dereferences the transport
  973. Arguments:
  974. pTransport - the transport instance
  975. Return Value:
  976. STATUS_SUCCESS - the server transport was successfully dereferenced
  977. Other Status codes correspond to error situations.
  978. Notes:
  979. --*/
  980. {
  981. NTSTATUS Status = STATUS_SUCCESS;
  982. BOOLEAN AttachToSystemProcess = FALSE;
  983. KAPC_STATE ApcState;
  984. PAGED_CODE();
  985. if (pTransport != NULL) {
  986. LONG FinalRefCount;
  987. FinalRefCount = InterlockedDecrement(&pTransport->SwizzleCount);
  988. if (FinalRefCount == 0) {
  989. SmbCeRemoveTransport(pTransport);
  990. if (IoGetCurrentProcess() != RxGetRDBSSProcess()) {
  991. KeStackAttachProcess(RxGetRDBSSProcess(),&ApcState);
  992. AttachToSystemProcess = TRUE;
  993. }
  994. RxCeTearDownAddress(&pTransport->RxCeAddress);
  995. RxCeTearDownTransport(&pTransport->RxCeTransport);
  996. if (AttachToSystemProcess) {
  997. KeUnstackDetachProcess(&ApcState);
  998. }
  999. RxFreePool(pTransport);
  1000. }
  1001. } else {
  1002. Status = STATUS_INVALID_PARAMETER;
  1003. }
  1004. return Status;
  1005. }
  1006. HANDLE MRxSmbTdiNotificationHandle = NULL;
  1007. KEVENT TdiNetStartupCompletionEvent;
  1008. LONG TdiBindRequestsActive = 0;
  1009. BOOLEAN TdiPnpNetReadyEventReceived = FALSE;
  1010. // The TRANSPORT_BIND_CONTEXT contains the result of the priority determination
  1011. // as well as the name. The priority is used to order the transports in the order
  1012. // in which connection attempts will be made
  1013. typedef struct _TRANSPORT_BIND_CONTEXT_ {
  1014. ULONG Priority;
  1015. UNICODE_STRING TransportName;
  1016. } TRANSPORT_BIND_CONTEXT, *PTRANSPORT_BIND_CONTEXT;
  1017. VOID
  1018. SmbCeSignalNetReadyEvent()
  1019. /*++
  1020. Routine Description:
  1021. The routine signals the net ready event if all the bind requests
  1022. have been completed and if the net ready event has been received from TDI
  1023. Arguments:
  1024. --*/
  1025. {
  1026. BOOLEAN SignalNetReadyEvent = FALSE;
  1027. SmbCeAcquireSpinLock();
  1028. if (TdiPnpNetReadyEventReceived &&
  1029. TdiBindRequestsActive == 0) {
  1030. SignalNetReadyEvent = TRUE;
  1031. }
  1032. SmbCeReleaseSpinLock();
  1033. if (SignalNetReadyEvent) {
  1034. KeSetEvent(
  1035. &TdiNetStartupCompletionEvent,
  1036. IO_NETWORK_INCREMENT,
  1037. FALSE);
  1038. }
  1039. }
  1040. VOID
  1041. MRxSmbpBindTransportCallback(
  1042. IN PTRANSPORT_BIND_CONTEXT pTransportContext)
  1043. /*++
  1044. Routine Description:
  1045. TDI calls this routine whenever a transport creates a new device object.
  1046. Arguments:
  1047. TransportName - the name of the newly created device object
  1048. TransportBindings - the transport bindings ( multi sz)
  1049. --*/
  1050. {
  1051. NTSTATUS Status = STATUS_SUCCESS;
  1052. PSMBCE_TRANSPORT pTransport;
  1053. PUNICODE_STRING pTransportName;
  1054. PAGED_CODE();
  1055. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1056. pTransportName = &pTransportContext->TransportName;
  1057. RxDbgTrace( 0, Dbg, ("MrxSmbpBindTransportCallback, Transport Name = %wZ\n", pTransportName ));
  1058. pTransport = RxAllocatePoolWithTag(
  1059. NonPagedPool,
  1060. sizeof(SMBCE_TRANSPORT),
  1061. MRXSMB_TRANSPORT_POOLTAG);
  1062. if (pTransport != NULL) {
  1063. Status = RxCeBuildTransport(
  1064. &pTransport->RxCeTransport,
  1065. pTransportName,
  1066. 0xffff);
  1067. if (Status == STATUS_SUCCESS) {
  1068. PRXCE_TRANSPORT_PROVIDER_INFO pProviderInfo;
  1069. pProviderInfo = pTransport->RxCeTransport.pProviderInfo;
  1070. if (!(pProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) ||
  1071. !(pProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY)) {
  1072. RxCeTearDownTransport(
  1073. &pTransport->RxCeTransport);
  1074. Status = STATUS_PROTOCOL_UNREACHABLE;
  1075. RxFreePool(pTransport);
  1076. }
  1077. }
  1078. } else {
  1079. Status = STATUS_INSUFFICIENT_RESOURCES;
  1080. }
  1081. if (Status == STATUS_SUCCESS) {
  1082. // The connection capabilities match the capabilities required by the
  1083. // SMB mini redirector. Attempt to register the local address with the
  1084. // transport and if successful update the local transport list to include
  1085. // this transport for future connection considerations.
  1086. OEM_STRING OemServerName;
  1087. CHAR TransportAddressBuffer[TDI_TRANSPORT_ADDRESS_LENGTH +
  1088. TDI_ADDRESS_LENGTH_NETBIOS];
  1089. PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)TransportAddressBuffer;
  1090. PTDI_ADDRESS_NETBIOS pNetbiosAddress = (PTDI_ADDRESS_NETBIOS)pTransportAddress->Address[0].Address;
  1091. pTransportAddress->TAAddressCount = 1;
  1092. pTransportAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
  1093. pTransportAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1094. pNetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1095. OemServerName.MaximumLength = NETBIOS_NAME_LEN;
  1096. OemServerName.Buffer = pNetbiosAddress->NetbiosName;
  1097. Status = RtlUpcaseUnicodeStringToOemString(
  1098. &OemServerName,
  1099. &SmbCeContext.ComputerName,
  1100. FALSE);
  1101. if (NT_SUCCESS(Status)) {
  1102. // Ensure that the name is always of the desired length by padding
  1103. // white space to the end.
  1104. RtlCopyMemory(
  1105. &OemServerName.Buffer[OemServerName.Length],
  1106. " ",
  1107. NETBIOS_NAME_LEN - OemServerName.Length);
  1108. OemServerName.Buffer[NETBIOS_NAME_LEN - 1] = '\0';
  1109. // Register the Transport address for this mini redirector with the connection
  1110. // engine.
  1111. Status = RxCeBuildAddress(
  1112. &pTransport->RxCeAddress,
  1113. &pTransport->RxCeTransport,
  1114. pTransportAddress,
  1115. &MRxSmbVctAddressEventHandler,
  1116. &SmbCeContext);
  1117. if (Status == STATUS_SUCCESS) {
  1118. RxDbgTrace( 0, Dbg, ("MRxSmbTransportUpdateHandler: Adding new transport\n"));
  1119. pTransport->Active = TRUE;
  1120. pTransport->Priority = pTransportContext->Priority;
  1121. pTransport->SwizzleCount = 0;
  1122. pTransport->ObjectCategory = SMB_SERVER_TRANSPORT_CATEGORY;
  1123. pTransport->ObjectType = SMBCEDB_OT_TRANSPORT;
  1124. pTransport->State = 0;
  1125. pTransport->Flags = 0;
  1126. SmbCeAddTransport(pTransport);
  1127. RxDbgTrace( 0, Dbg, ("MrxSmbpBindTransportCallback, Transport %wZ added\n", pTransportName ));
  1128. } else {
  1129. RxDbgTrace( 0, Dbg, ("MRxSmbTransportUpdateHandler: Address registration failed %lx\n",Status));
  1130. }
  1131. }
  1132. if (Status != STATUS_SUCCESS) {
  1133. RxDbgTrace( 0, Dbg, ("MrxSmbpBindTransportCallback, Transport %wZ unreachable 0x%x\n",
  1134. pTransportName, Status ));
  1135. RxCeTearDownTransport(
  1136. &pTransport->RxCeTransport);
  1137. Status = STATUS_PROTOCOL_UNREACHABLE;
  1138. RxFreePool(pTransport);
  1139. }
  1140. }
  1141. InterlockedDecrement(&TdiBindRequestsActive);
  1142. SmbCeSignalNetReadyEvent();
  1143. }
  1144. VOID
  1145. MRxSmbpBindTransportWorkerThreadRoutine(
  1146. IN PTRANSPORT_BIND_CONTEXT pTransportContext)
  1147. /*++
  1148. Routine Description:
  1149. The TDI callbacks always do not occur in the context of the FSP process.
  1150. Since there are a few TDi interfaces that accept handles we need to ensure
  1151. that such calls always gets funnelled back to the FSP.
  1152. Arguments:
  1153. pTransportContext - the transport binding context
  1154. --*/
  1155. {
  1156. PAGED_CODE();
  1157. MRxSmbpBindTransportCallback(pTransportContext);
  1158. RxFreePool(pTransportContext);
  1159. }
  1160. VOID
  1161. MRxSmbpUnbindTransportCallback(
  1162. PSMBCE_TRANSPORT pTransport)
  1163. /*++
  1164. Routine Description:
  1165. The Unbind callback routine which is always executed in the context of the
  1166. RDR process so that handles can be closed correctly
  1167. Arguments:
  1168. pTransport - the transport for which the PNP_OP_DEL was received
  1169. Notes:
  1170. On entry to this routine the appropriate transport must have been referenced
  1171. This routine will dereference it and invalidate the existing exchanges using
  1172. this transport.
  1173. --*/
  1174. {
  1175. PAGED_CODE();
  1176. // Remove this transport from the list of transports under consideration
  1177. // in the mini redirector.
  1178. SmbCeRemoveTransport(pTransport);
  1179. // Enumerate the servers and mark those servers utilizing this transport
  1180. // as having an invalid transport.
  1181. SmbCeHandleTransportInvalidation(pTransport);
  1182. // dereference the transport
  1183. SmbCeDereferenceTransport(pTransport);
  1184. }
  1185. VOID
  1186. MRxSmbpOverrideBindingPriority(
  1187. PUNICODE_STRING pTransportName,
  1188. PULONG pPriority
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. This function obtains a overriding priority value from the registry for a given
  1193. transport.
  1194. The priority of a transport controls the order in which connections are accepted. It is
  1195. sometimes useful for a customer to control which transport is used first in the redirector.
  1196. The priority is usually determined by the order of the transports in the binding list. With
  1197. the new Connections UI model for network setup, it will no longer be possible to adjust
  1198. the order of the bindings in the binding list. Thus, another mechanism is needed when the
  1199. user wants to override the priority assigned to a given binding.
  1200. Arguments:
  1201. pTransportName - pointer to UNICODE_STRING descriptor for transport string, for example
  1202. "\Device\Netbt_tcpip_{guid}"
  1203. pPriority - pointer to LONG to receive new priority on success, otherwise not touched
  1204. Return Value:
  1205. None
  1206. --*/
  1207. {
  1208. WCHAR valueBuffer[128];
  1209. UNICODE_STRING path, value, key;
  1210. USHORT length,ulength;
  1211. OBJECT_ATTRIBUTES objectAttributes;
  1212. NTSTATUS status;
  1213. HANDLE parametersHandle;
  1214. ULONG temp;
  1215. PAGED_CODE();
  1216. // Validate input
  1217. if (pTransportName->Length == 0) {
  1218. return;
  1219. }
  1220. // Open parameters key
  1221. RtlInitUnicodeString( &path, SMBMRX_MINIRDR_PARAMETERS );
  1222. InitializeObjectAttributes(
  1223. &objectAttributes,
  1224. &path,
  1225. OBJ_CASE_INSENSITIVE,
  1226. NULL,
  1227. NULL
  1228. );
  1229. status = ZwOpenKey (&parametersHandle, KEY_READ, &objectAttributes);
  1230. if (!NT_SUCCESS(status)) {
  1231. return;
  1232. }
  1233. // Construct value name = "BindingPriority" + transportname
  1234. // First, find the last slash. Then form the value from the prefix and
  1235. // the remainder of the transport name.
  1236. ulength = pTransportName->Length / sizeof(WCHAR);
  1237. for( length = ulength - 1; length != 0; length-- ) {
  1238. if (pTransportName->Buffer[length] == L'\\') {
  1239. break;
  1240. }
  1241. }
  1242. length++;
  1243. key.Buffer = pTransportName->Buffer + length;
  1244. key.Length = (ulength - length) * sizeof(WCHAR);
  1245. value.Buffer = valueBuffer;
  1246. value.MaximumLength = 128 * sizeof(WCHAR);
  1247. value.Length = 0;
  1248. RtlAppendUnicodeToString( &value, L"BindingPriority" );
  1249. RtlAppendUnicodeStringToString( &value, &key );
  1250. // Check if the value is present. If so, replace priority
  1251. // A value of zero is valid and indicates do not bind this one
  1252. status = MRxSmbGetUlongRegistryParameter(
  1253. parametersHandle,
  1254. value.Buffer,
  1255. (PULONG)&temp,
  1256. FALSE );
  1257. if (NT_SUCCESS(status)) {
  1258. *pPriority = temp;
  1259. }
  1260. ZwClose(parametersHandle);
  1261. }
  1262. VOID
  1263. MRxSmbPnPBindingHandler(
  1264. IN TDI_PNP_OPCODE PnPOpcode,
  1265. IN PUNICODE_STRING pTransportName,
  1266. IN PWSTR BindingList)
  1267. /*++
  1268. Routine Description:
  1269. The TDI callbacks routine for binding changes
  1270. Arguments:
  1271. PnPOpcode - the PNP op code
  1272. pTransportName - the transport name
  1273. BindingList - the binding order
  1274. --*/
  1275. {
  1276. ULONG Priority;
  1277. NTSTATUS Status;
  1278. PAGED_CODE();
  1279. switch (PnPOpcode) {
  1280. case TDI_PNP_OP_ADD:
  1281. {
  1282. BOOLEAN fBindToTransport = FALSE;
  1283. PWSTR pSmbMRxTransports;
  1284. UNICODE_STRING SmbMRxTransport;
  1285. Status = SmbCeGetConfigurationInformation();
  1286. if (Status != STATUS_SUCCESS) {
  1287. return;
  1288. }
  1289. pSmbMRxTransports = (PWSTR)SmbCeContext.Transports.Buffer;
  1290. Priority = 1;
  1291. while (*pSmbMRxTransports) {
  1292. SmbMRxTransport.Length = wcslen(pSmbMRxTransports) * sizeof(WCHAR);
  1293. if (SmbMRxTransport.Length == pTransportName->Length) {
  1294. SmbMRxTransport.MaximumLength = SmbMRxTransport.Length;
  1295. SmbMRxTransport.Buffer = pSmbMRxTransports;
  1296. if (RtlCompareUnicodeString(
  1297. &SmbMRxTransport,
  1298. pTransportName,
  1299. TRUE) == 0) {
  1300. fBindToTransport = TRUE;
  1301. break;
  1302. }
  1303. }
  1304. pSmbMRxTransports += (SmbMRxTransport.Length / sizeof(WCHAR) + 1);
  1305. Priority++;
  1306. }
  1307. // Provide a local registry means to alter binding priority
  1308. // if (fBindToTransport) {
  1309. // MRxSmbpOverrideBindingPriority( pTransportName, &Priority );
  1310. // fBindToTransport = (Priority != 0);
  1311. // }
  1312. if (fBindToTransport) {
  1313. InterlockedIncrement(&TdiBindRequestsActive);
  1314. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1315. TRANSPORT_BIND_CONTEXT TransportContext;
  1316. TransportContext.Priority = Priority;
  1317. TransportContext.TransportName = *pTransportName;
  1318. MRxSmbpBindTransportCallback(&TransportContext);
  1319. } else {
  1320. PTRANSPORT_BIND_CONTEXT pNewTransportContext;
  1321. pNewTransportContext = RxAllocatePoolWithTag(
  1322. PagedPool,
  1323. sizeof(TRANSPORT_BIND_CONTEXT) + pTransportName->Length,
  1324. MRXSMB_TRANSPORT_POOLTAG);
  1325. if (pNewTransportContext != NULL) {
  1326. pNewTransportContext->Priority = Priority;
  1327. pNewTransportContext->TransportName.MaximumLength = pTransportName->MaximumLength;
  1328. pNewTransportContext->TransportName.Length = pTransportName->Length;
  1329. pNewTransportContext->TransportName.Buffer = (PWCHAR)((PBYTE)pNewTransportContext +
  1330. sizeof(TRANSPORT_BIND_CONTEXT));
  1331. RtlCopyMemory(
  1332. pNewTransportContext->TransportName.Buffer,
  1333. pTransportName->Buffer,
  1334. pTransportName->Length);
  1335. Status = RxDispatchToWorkerThread(
  1336. MRxSmbDeviceObject,
  1337. CriticalWorkQueue,
  1338. MRxSmbpBindTransportWorkerThreadRoutine,
  1339. pNewTransportContext);
  1340. } else {
  1341. Status = STATUS_INSUFFICIENT_RESOURCES;
  1342. }
  1343. if (Status != STATUS_SUCCESS) {
  1344. InterlockedDecrement(&TdiBindRequestsActive);
  1345. SmbCeSignalNetReadyEvent();
  1346. }
  1347. }
  1348. }
  1349. }
  1350. break;
  1351. case TDI_PNP_OP_DEL:
  1352. {
  1353. PSMBCE_TRANSPORT pTransport;
  1354. pTransport = SmbCeFindTransport(pTransportName);
  1355. if (pTransport != NULL) {
  1356. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1357. MRxSmbpUnbindTransportCallback(pTransport);
  1358. } else {
  1359. Status = RxDispatchToWorkerThread(
  1360. MRxSmbDeviceObject,
  1361. CriticalWorkQueue,
  1362. MRxSmbpUnbindTransportCallback,
  1363. pTransport);
  1364. }
  1365. }
  1366. }
  1367. break;
  1368. case TDI_PNP_OP_UPDATE:
  1369. {
  1370. }
  1371. break;
  1372. case TDI_PNP_OP_NETREADY:
  1373. {
  1374. TdiPnpNetReadyEventReceived = TRUE;
  1375. SmbCeSignalNetReadyEvent();
  1376. }
  1377. break;
  1378. default:
  1379. break;
  1380. }
  1381. }
  1382. NTSTATUS
  1383. MRxSmbPnPPowerHandler(
  1384. IN PUNICODE_STRING DeviceName,
  1385. IN PNET_PNP_EVENT PowerEvent,
  1386. IN PTDI_PNP_CONTEXT Context1,
  1387. IN PTDI_PNP_CONTEXT Context2
  1388. )
  1389. /*++
  1390. Routine Description:
  1391. This routine deals with power changes
  1392. Notes:
  1393. The implementation needs to be completed
  1394. --*/
  1395. {
  1396. NTSTATUS Status;
  1397. LONG NumberOfActiveOpens;
  1398. Status = STATUS_SUCCESS;
  1399. FsRtlEnterFileSystem();
  1400. RxPurgeAllFobxs(MRxSmbDeviceObject);
  1401. RxScavengeAllFobxs(MRxSmbDeviceObject);
  1402. NumberOfActiveOpens = MRxSmbNumberOfSrvOpens;
  1403. switch (PowerEvent->NetEvent) {
  1404. case NetEventQueryPower:
  1405. {
  1406. // If the redirector were to return an error on this request there
  1407. // is no underlying support to tell the user about the files that
  1408. // are open. There are two approaches to doing this.. either the RDR
  1409. // rolls its own UI or the PNP manager provides the infra structure.
  1410. // The problem with the former is that hibernation becomes a painstaking
  1411. // process wherein the user has to contend with a variety of UI.
  1412. // Till this is resolved the decision was to use the power mgmt. API
  1413. // to manage system initiated hibernate requests and succeed user
  1414. // initiated requests after appropriate purging/scavenging.
  1415. if (MRxSmbNumberOfSrvOpens > 0) {
  1416. DbgPrint(
  1417. "RDR: PNP Hibernate Request Status %lx Number of Opens %lx\n",
  1418. Status,
  1419. MRxSmbNumberOfSrvOpens);
  1420. }
  1421. Status = STATUS_SUCCESS;
  1422. }
  1423. break;
  1424. case NetEventQueryRemoveDevice:
  1425. {
  1426. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1427. ULONG NumberOfFilesOpen = 0;
  1428. PSMBCE_TRANSPORT pTransport = NULL;
  1429. pTransport = SmbCeFindTransport(DeviceName);
  1430. if (pTransport != NULL) {
  1431. SmbCeAcquireSpinLock();
  1432. pServerEntry = SmbCeGetFirstServerEntry();
  1433. while (pServerEntry != NULL) {
  1434. if ((pServerEntry->pTransport != NULL) &&
  1435. (pTransport == pServerEntry->pTransport->pTransport)) {
  1436. NumberOfFilesOpen += pServerEntry->Server.NumberOfSrvOpens;
  1437. }
  1438. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1439. }
  1440. SmbCeReleaseSpinLock();
  1441. SmbCeDereferenceTransport(pTransport);
  1442. }
  1443. }
  1444. break;
  1445. default:
  1446. break;
  1447. }
  1448. FsRtlExitFileSystem();
  1449. return Status;
  1450. }
  1451. NTSTATUS
  1452. MRxSmbRegisterForPnpNotifications()
  1453. /*++
  1454. Routine Description:
  1455. This routine registers with TDI for receiving transport notifications
  1456. --*/
  1457. {
  1458. NTSTATUS Status = STATUS_SUCCESS;
  1459. PAGED_CODE();
  1460. if(MRxSmbTdiNotificationHandle == NULL ) {
  1461. UNICODE_STRING ClientName;
  1462. TDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo;
  1463. RtlInitUnicodeString(&ClientName,L"LanmanWorkStation");
  1464. ClientInterfaceInfo.MajorTdiVersion = 2;
  1465. ClientInterfaceInfo.MinorTdiVersion = 0;
  1466. ClientInterfaceInfo.Unused = 0;
  1467. ClientInterfaceInfo.ClientName = &ClientName;
  1468. ClientInterfaceInfo.BindingHandler = MRxSmbPnPBindingHandler;
  1469. ClientInterfaceInfo.AddAddressHandler = NULL;
  1470. ClientInterfaceInfo.DelAddressHandler = NULL;
  1471. ClientInterfaceInfo.PnPPowerHandler = MRxSmbPnPPowerHandler;
  1472. KeInitializeEvent(
  1473. &TdiNetStartupCompletionEvent,
  1474. NotificationEvent,
  1475. FALSE);
  1476. Status = TdiRegisterPnPHandlers (
  1477. &ClientInterfaceInfo,
  1478. sizeof(ClientInterfaceInfo),
  1479. &MRxSmbTdiNotificationHandle );
  1480. if (Status == STATUS_SUCCESS) {
  1481. LARGE_INTEGER WaitInterval;
  1482. WaitInterval.QuadPart = -( 10000 * 2 * 60 * 1000 );
  1483. Status = KeWaitForSingleObject(
  1484. &TdiNetStartupCompletionEvent,
  1485. Executive,
  1486. KernelMode,
  1487. TRUE,
  1488. &WaitInterval);
  1489. }
  1490. }
  1491. return Status;
  1492. }
  1493. NTSTATUS
  1494. MRxSmbDeregisterForPnpNotifications()
  1495. /*++
  1496. Routine Description:
  1497. This routine deregisters the TDI notification mechanism
  1498. Notes:
  1499. --*/
  1500. {
  1501. NTSTATUS Status = STATUS_SUCCESS;
  1502. PAGED_CODE();
  1503. if( MRxSmbTdiNotificationHandle != NULL ) {
  1504. Status = TdiDeregisterPnPHandlers( MRxSmbTdiNotificationHandle );
  1505. if( NT_SUCCESS( Status ) ) {
  1506. MRxSmbTdiNotificationHandle = NULL;
  1507. }
  1508. }
  1509. return Status;
  1510. }
  1511. PSMBCE_TRANSPORT_ARRAY
  1512. SmbCeReferenceTransportArray(VOID)
  1513. /*++
  1514. Routine Description:
  1515. This routine references and returns the current transport array instance
  1516. Return Value:
  1517. PSMBCE_TRANSPORT_ARRAY - the pointer of the current transport array instance
  1518. Notes:
  1519. --*/
  1520. {
  1521. KIRQL SavedIrql;
  1522. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  1523. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  1524. pTransportArray = MRxSmbTransports.pTransportArray;
  1525. if (pTransportArray != NULL) {
  1526. InterlockedIncrement(&pTransportArray->ReferenceCount);
  1527. }
  1528. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  1529. return pTransportArray;
  1530. }
  1531. NTSTATUS
  1532. SmbCeDereferenceTransportArray(
  1533. PSMBCE_TRANSPORT_ARRAY pTransportArray)
  1534. /*++
  1535. Routine Description:
  1536. This routine dereferences the transport array instance
  1537. Arguments:
  1538. pTransportArray - the transport array instance
  1539. Return Value:
  1540. STATUS_SUCCESS - the server transport was successfully dereferenced
  1541. Other Status codes correspond to error situations.
  1542. Notes:
  1543. --*/
  1544. {
  1545. KIRQL SavedIrql;
  1546. NTSTATUS Status = STATUS_SUCCESS;
  1547. PAGED_CODE();
  1548. if (pTransportArray != NULL) {
  1549. ASSERT( pTransportArray->ReferenceCount > 0 );
  1550. if(InterlockedDecrement(&pTransportArray->ReferenceCount)==0) {
  1551. ULONG i;
  1552. for(i=0;i<pTransportArray->Count;i++) {
  1553. SmbCeDereferenceTransport(pTransportArray->SmbCeTransports[i]);
  1554. }
  1555. RxFreePool(pTransportArray->SmbCeTransports);
  1556. RxFreePool(pTransportArray->LocalAddresses);
  1557. RxFreePool(pTransportArray);
  1558. }
  1559. } else {
  1560. Status = STATUS_INVALID_PARAMETER;
  1561. }
  1562. return Status;
  1563. }
  1564. NTSTATUS
  1565. SmbCeIsServerAvailable(
  1566. PUNICODE_STRING Name
  1567. )
  1568. /*++
  1569. Routine Description:
  1570. This routine scans the list of "unreachable" servers and returns the status
  1571. of the last failed connection attempt.
  1572. Return:
  1573. STATUS_SUCCESS -> we have no reason to believe this server is unreachable
  1574. other -> server is unreachable for this reason
  1575. --*/
  1576. {
  1577. PUNAVAILABLE_SERVER server;
  1578. LARGE_INTEGER now;
  1579. NTSTATUS status = STATUS_SUCCESS;
  1580. PAGED_CODE();
  1581. KeQueryTickCount( &now );
  1582. ExAcquireResourceExclusive( &UnavailableServerListResource, TRUE );
  1583. for( server = (PUNAVAILABLE_SERVER)UnavailableServerList.Flink;
  1584. server != (PUNAVAILABLE_SERVER)&UnavailableServerList;
  1585. server = (PUNAVAILABLE_SERVER)server->ListEntry.Flink ) {
  1586. //
  1587. // If this entry has timed out, remove it.
  1588. //
  1589. if( now.QuadPart > server->Time.QuadPart ) {
  1590. PUNAVAILABLE_SERVER tmp;
  1591. //
  1592. // Unlink this entry from the list and discard it
  1593. //
  1594. tmp = (PUNAVAILABLE_SERVER)(server->ListEntry.Blink);
  1595. RemoveEntryList( &server->ListEntry );
  1596. RxFreePool( server );
  1597. server = tmp;
  1598. continue;
  1599. }
  1600. //
  1601. // See if this entry is the one we want
  1602. //
  1603. if( RtlCompareUnicodeString( &server->Name, Name, TRUE ) == 0 ) {
  1604. status = server->Status;
  1605. RxDbgTrace(0, Dbg, ("SmbCeIsServerAvailable: Found %wZ %X\n",
  1606. &server->Name, status ));
  1607. }
  1608. }
  1609. ExReleaseResource( &UnavailableServerListResource );
  1610. return status;
  1611. }
  1612. VOID
  1613. SmbCeServerIsUnavailable(
  1614. PUNICODE_STRING Name,
  1615. NTSTATUS Status
  1616. )
  1617. {
  1618. PUNAVAILABLE_SERVER server;
  1619. LARGE_INTEGER CurrentTime;
  1620. LARGE_INTEGER ExpiryTimeInTicks;
  1621. PAGED_CODE();
  1622. server = (PUNAVAILABLE_SERVER)RxAllocatePoolWithTag(
  1623. PagedPool,
  1624. sizeof( *server ) + Name->Length,
  1625. MRXSMB_TRANSPORT_POOLTAG
  1626. );
  1627. if( server == NULL ) {
  1628. return;
  1629. }
  1630. RxDbgTrace(0, Dbg, ("SmbCeServerIsUnavailable: Add %wZ %X\n", Name, Status ));
  1631. server->Name.Buffer = (PUSHORT)(server + 1);
  1632. server->Name.MaximumLength = Name->Length;
  1633. RtlCopyUnicodeString( &server->Name, Name );
  1634. KeQueryTickCount( &CurrentTime );
  1635. ExpiryTimeInTicks.QuadPart = (1000 * 1000 * 10) / KeQueryTimeIncrement();
  1636. ExpiryTimeInTicks.QuadPart = UNAVAILABLE_SERVER_TIME * ExpiryTimeInTicks.QuadPart;
  1637. server->Time.QuadPart = CurrentTime.QuadPart + ExpiryTimeInTicks.QuadPart;
  1638. server->Status = Status;
  1639. ExAcquireResourceExclusive( &UnavailableServerListResource, TRUE );
  1640. InsertHeadList( &UnavailableServerList, &server->ListEntry );
  1641. ExReleaseResource( &UnavailableServerListResource );
  1642. }
  1643. VOID
  1644. SmbCeDiscardUnavailableServerList(
  1645. )
  1646. {
  1647. PUNAVAILABLE_SERVER server;
  1648. PAGED_CODE();
  1649. RxDbgTrace(0, Dbg, ("SmbCeDiscardUnavailableServerList\n" ));
  1650. ExAcquireResourceExclusive( &UnavailableServerListResource, TRUE );
  1651. while( UnavailableServerList.Flink != &UnavailableServerList ) {
  1652. server = (PUNAVAILABLE_SERVER)UnavailableServerList.Flink;
  1653. RemoveEntryList( &server->ListEntry );
  1654. RxFreePool( server );
  1655. }
  1656. ExReleaseResource( &UnavailableServerListResource );
  1657. }