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.

3235 lines
96 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. transport.c
  5. Abstract:
  6. This module implements all transport related functions in the SMB connection engine
  7. Revision History:
  8. Balan Sethu Raman [SethuR] 6-March-1995
  9. Will Lees (wlees) 08-Sep-1997 Initialize MoTcp Device
  10. Notes:
  11. --*/
  12. #include "precomp.h"
  13. #include <nbtioctl.h>
  14. #pragma hdrstop
  15. #include "ntddbrow.h"
  16. #include "tdikrnl.h"
  17. #include "dfsfsctl.h"
  18. NTSTATUS
  19. SmbCeIsServerAvailable(
  20. PUNICODE_STRING Name
  21. );
  22. VOID
  23. SmbCeServerIsUnavailable(
  24. PUNICODE_STRING Name,
  25. NTSTATUS Status
  26. );
  27. VOID
  28. SmbCeDiscardUnavailableServerList( );
  29. VOID
  30. MRxSmbpOverrideBindingPriority(
  31. PUNICODE_STRING pTransportName,
  32. PULONG pPriority
  33. );
  34. VOID
  35. MRxSmbPnPBindingHandler(
  36. IN TDI_PNP_OPCODE PnPOpcode,
  37. IN PUNICODE_STRING pTransportName,
  38. IN PWSTR BindingList
  39. );
  40. NTSTATUS
  41. MRxSmbPnPPowerHandler(
  42. IN PUNICODE_STRING DeviceName,
  43. IN PNET_PNP_EVENT PowerEvent,
  44. IN PTDI_PNP_CONTEXT Context1,
  45. IN PTDI_PNP_CONTEXT Context2
  46. );
  47. VOID
  48. SmbMRxNotifyChangesToNetBt(
  49. IN TDI_PNP_OPCODE PnPOpcode,
  50. IN PUNICODE_STRING DeviceName,
  51. IN PWSTR MultiSZBindList
  52. );
  53. #ifdef ALLOC_PRAGMA
  54. #pragma alloc_text(PAGE, SmbCeFindTransport)
  55. #pragma alloc_text(PAGE, SmbCepInitializeServerTransport)
  56. #pragma alloc_text(PAGE, SmbCeInitializeExchangeTransport)
  57. #pragma alloc_text(PAGE, SmbCeUninitializeExchangeTransport)
  58. #pragma alloc_text(PAGE, SmbCepDereferenceTransport)
  59. #pragma alloc_text(PAGE, MRxSmbpBindTransportCallback)
  60. #pragma alloc_text(PAGE, MRxSmbpBindTransportWorkerThreadRoutine)
  61. #pragma alloc_text(PAGE, MRxSmbBindTransportCallback)
  62. #pragma alloc_text(PAGE, MRxSmbUnbindTransportCallback)
  63. #pragma alloc_text(PAGE, MRxSmbRegisterForPnpNotifications)
  64. #pragma alloc_text(PAGE, MRxSmbDeregisterForPnpNotifications)
  65. #pragma alloc_text(PAGE, MRxSmbpBindTransportCallback)
  66. #pragma alloc_text(PAGE, MRxSmbpBindTransportWorkerThreadRoutine)
  67. #pragma alloc_text(PAGE, MRxSmbpUnbindTransportCallback)
  68. #pragma alloc_text(PAGE, MRxSmbpOverrideBindingPriority)
  69. #pragma alloc_text(PAGE, MRxSmbPnPBindingHandler)
  70. #pragma alloc_text(PAGE, MRxSmbRegisterForPnpNotifications)
  71. #pragma alloc_text(PAGE, MRxSmbDeregisterForPnpNotifications)
  72. #pragma alloc_text(PAGE, SmbCePnpBindBrowser)
  73. #pragma alloc_text(PAGE, SmbCeDereferenceTransportArray)
  74. #pragma alloc_text(PAGE, SmbCeIsServerAvailable)
  75. #pragma alloc_text(PAGE, SmbCeServerIsUnavailable)
  76. #pragma alloc_text(PAGE, SmbCeDiscardUnavailableServerList)
  77. #endif
  78. SMBCE_TRANSPORTS MRxSmbTransports;
  79. //
  80. // The head of the list of servers that are currently unavailable
  81. //
  82. LIST_ENTRY UnavailableServerList = { &UnavailableServerList, &UnavailableServerList };
  83. //
  84. // Each entry in the UnavailableServerList is one of these:
  85. //
  86. typedef struct {
  87. LIST_ENTRY ListEntry;
  88. UNICODE_STRING Name; // Name of server that is unavailable
  89. NTSTATUS Status; // Status received when we tried to connect to it
  90. LARGE_INTEGER Time; // Time when we last attempted to connect
  91. } *PUNAVAILABLE_SERVER;
  92. //
  93. // Protects UnavailableServerList
  94. //
  95. ERESOURCE UnavailableServerListResource = {0};
  96. //
  97. // Time (seconds) that we keep an entry in the UnavailableServerList.
  98. // We will not retry a connection attempt to a server
  99. // for UNAVAILABLE_SERVER_TIME seconds
  100. //
  101. #define UNAVAILABLE_SERVER_TIME 10
  102. RXDT_DefineCategory(TRANSPRT);
  103. #define Dbg (DEBUG_TRACE_TRANSPRT)
  104. extern NTSTATUS
  105. SmbCePnpBindBrowser(
  106. PUNICODE_STRING pTransportName,
  107. BOOLEAN IsBind);
  108. NTSTATUS
  109. MRxSmbInitializeTransport()
  110. /*++
  111. Routine Description:
  112. This routine initializes the transport related data structures
  113. Returns:
  114. STATUS_SUCCESS if the transport data structures was successfully initialized
  115. Notes:
  116. --*/
  117. {
  118. KeInitializeSpinLock(&MRxSmbTransports.Lock);
  119. MRxSmbTransports.pTransportArray = NULL;
  120. ExInitializeResource( &UnavailableServerListResource );
  121. return STATUS_SUCCESS;
  122. }
  123. NTSTATUS
  124. MRxSmbUninitializeTransport()
  125. /*++
  126. Routine Description:
  127. This routine uninitializes the transport related data structures
  128. Notes:
  129. --*/
  130. {
  131. PSMBCE_TRANSPORT pTransport;
  132. KIRQL SavedIrql;
  133. ULONG TransportCount = 0;
  134. PSMBCE_TRANSPORT_ARRAY pTransportArray = NULL;
  135. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  136. if (MRxSmbTransports.pTransportArray != NULL) {
  137. pTransportArray = MRxSmbTransports.pTransportArray;
  138. MRxSmbTransports.pTransportArray = NULL;
  139. }
  140. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  141. if (pTransportArray != NULL) {
  142. SmbCeDereferenceTransportArray(pTransportArray);
  143. }
  144. SmbCeDiscardUnavailableServerList();
  145. ExDeleteResource( &UnavailableServerListResource );
  146. return STATUS_SUCCESS;
  147. }
  148. NTSTATUS
  149. SmbCeAddTransport(
  150. PSMBCE_TRANSPORT pNewTransport)
  151. /*++
  152. Routine Description:
  153. This routine adds a new instance to the known list of transports
  154. Parameters:
  155. pNewTransport -- the transport instance to be added
  156. Notes:
  157. --*/
  158. {
  159. NTSTATUS Status = STATUS_SUCCESS;
  160. KIRQL SavedIrql;
  161. LONG Count;
  162. PSMBCE_TRANSPORT_ARRAY pNewTransportArray = NULL;
  163. PSMBCE_TRANSPORT_ARRAY pOldTransportArray;
  164. PSMBCE_TRANSPORT *pTransports = NULL;
  165. PRXCE_ADDRESS *LocalAddresses = NULL;
  166. BOOLEAN SignalCscAgent = FALSE;
  167. SmbCeAcquireResource();
  168. pOldTransportArray = SmbCeReferenceTransportArray();
  169. if (pOldTransportArray != NULL)
  170. Count = pOldTransportArray->Count + 1;
  171. else
  172. Count = 1;
  173. pNewTransportArray = (PSMBCE_TRANSPORT_ARRAY)RxAllocatePoolWithTag(
  174. NonPagedPool,
  175. sizeof(SMBCE_TRANSPORT_ARRAY),
  176. MRXSMB_TRANSPORT_POOLTAG);
  177. if (pNewTransportArray == NULL) {
  178. Status = STATUS_INSUFFICIENT_RESOURCES;
  179. }
  180. if (Status == STATUS_SUCCESS) {
  181. pTransports = (PSMBCE_TRANSPORT *)RxAllocatePoolWithTag(
  182. NonPagedPool,
  183. Count * sizeof(PSMBCE_TRANSPORT),
  184. MRXSMB_TRANSPORT_POOLTAG);
  185. if (pTransports == NULL) {
  186. Status = STATUS_INSUFFICIENT_RESOURCES;
  187. }
  188. }
  189. if (Status == STATUS_SUCCESS) {
  190. LocalAddresses = (PRXCE_ADDRESS *)RxAllocatePoolWithTag(
  191. NonPagedPool,
  192. Count * sizeof(PRXCE_ADDRESS),
  193. MRXSMB_TRANSPORT_POOLTAG);
  194. if (LocalAddresses == NULL) {
  195. Status = STATUS_INSUFFICIENT_RESOURCES;
  196. }
  197. }
  198. if (Status == STATUS_SUCCESS) {
  199. LONG i;
  200. if (Count > 1) {
  201. PSMBCE_TRANSPORT *pOldTransports;
  202. pOldTransports = pOldTransportArray->SmbCeTransports;
  203. for (i=0;i<Count-1;i++) {
  204. if (pNewTransport->Priority < pOldTransports[i]->Priority) { // The lower number, the higher priority
  205. break;
  206. }
  207. pTransports[i] = pOldTransports[i];
  208. LocalAddresses[i] = &pOldTransports[i]->RxCeAddress;
  209. }
  210. pTransports[i] = pNewTransport;
  211. LocalAddresses[i] = &pNewTransport->RxCeAddress;
  212. for (;i<Count-1;i++) {
  213. pTransports[i+1] = pOldTransports[i];
  214. LocalAddresses[i+1] = &pOldTransports[i]->RxCeAddress;
  215. }
  216. } else {
  217. pTransports[0] = pNewTransport;
  218. LocalAddresses[0] = &pNewTransport->RxCeAddress;
  219. }
  220. for(i=0;i<Count;i++)
  221. SmbCeReferenceTransport(pTransports[i]);
  222. pNewTransportArray->ReferenceCount = 1;
  223. pNewTransportArray->Count = Count;
  224. pNewTransportArray->SmbCeTransports = &pTransports[0];
  225. pNewTransportArray->LocalAddresses = &LocalAddresses[0];
  226. // signal the CSC agent if this is the first transport
  227. SignalCscAgent = (pNewTransportArray->Count == 1);
  228. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  229. MRxSmbTransports.pTransportArray = pNewTransportArray;
  230. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  231. // Double dereferencing is necessary to ensure that
  232. // the old transport array is destroyed.
  233. SmbCeDereferenceTransportArray(pOldTransportArray);
  234. }
  235. SmbCeDereferenceTransportArray(pOldTransportArray);
  236. SmbCeReleaseResource();
  237. MRxSmbCscSignalNetStatus(TRUE, SignalCscAgent);
  238. if (Status != STATUS_SUCCESS) {
  239. if (pNewTransportArray != NULL) {
  240. RxFreePool(pNewTransportArray);
  241. }
  242. if (pTransports != NULL) {
  243. RxFreePool(pTransports);
  244. }
  245. if (LocalAddresses != NULL) {
  246. RxFreePool(LocalAddresses);
  247. }
  248. }
  249. SmbCeDiscardUnavailableServerList();
  250. return Status;
  251. }
  252. NTSTATUS
  253. SmbCeRemoveTransport(
  254. PSMBCE_TRANSPORT pTransport)
  255. /*++
  256. Routine Description:
  257. This routine removes a transport from the list of known transports
  258. Parameters:
  259. pTransport - the transport instance to be removed.
  260. Notes:
  261. --*/
  262. {
  263. NTSTATUS Status = STATUS_SUCCESS;
  264. KIRQL SavedIrql;
  265. LONG Count;
  266. PSMBCE_TRANSPORT_ARRAY pTransportArray = NULL;
  267. PSMBCE_TRANSPORT_ARRAY pOldTransportArray = NULL;
  268. PSMBCE_TRANSPORT *pTransports = NULL;
  269. PRXCE_ADDRESS *pLocalAddresses = NULL;
  270. BOOLEAN SignalCscAgent = FALSE, fReportRemovalToCSC=FALSE;
  271. SmbCeAcquireResource();
  272. pOldTransportArray = SmbCeReferenceTransportArray();
  273. if (pOldTransportArray != NULL) {
  274. LONG Index;
  275. BOOLEAN Found = FALSE;
  276. PSMBCE_TRANSPORT *pOldTransports;
  277. // Establish the fact that the given transport is part of the array.
  278. // if it is not then no further action is necessary
  279. pOldTransports = pOldTransportArray->SmbCeTransports;
  280. for (Index = 0; Index < (LONG)pOldTransportArray->Count; Index++) {
  281. if (pTransport == pOldTransports[Index]) {
  282. Found = TRUE;
  283. }
  284. }
  285. if (Found) {
  286. Count = pOldTransportArray->Count - 1;
  287. fReportRemovalToCSC = (pOldTransportArray->Count != 0);
  288. if (Count > 0) {
  289. pTransportArray = (PSMBCE_TRANSPORT_ARRAY)RxAllocatePoolWithTag(
  290. NonPagedPool,
  291. sizeof(SMBCE_TRANSPORT_ARRAY),
  292. MRXSMB_TRANSPORT_POOLTAG);
  293. if (pTransportArray == NULL) {
  294. Status = STATUS_INSUFFICIENT_RESOURCES;
  295. }
  296. if (Status == STATUS_SUCCESS) {
  297. pTransports = (PSMBCE_TRANSPORT *)RxAllocatePoolWithTag(
  298. NonPagedPool,
  299. Count * sizeof(PSMBCE_TRANSPORT),
  300. MRXSMB_TRANSPORT_POOLTAG);
  301. if (pTransports == NULL) {
  302. Status = STATUS_INSUFFICIENT_RESOURCES;
  303. }
  304. }
  305. if (Status == STATUS_SUCCESS) {
  306. pLocalAddresses = (PRXCE_ADDRESS *)RxAllocatePoolWithTag(
  307. NonPagedPool,
  308. Count * sizeof(PRXCE_ADDRESS),
  309. MRXSMB_TRANSPORT_POOLTAG);
  310. if (pLocalAddresses == NULL) {
  311. Status = STATUS_INSUFFICIENT_RESOURCES;
  312. }
  313. }
  314. if (Status == STATUS_SUCCESS) {
  315. LONG i, j;
  316. for (i=0, j=0;i<Count+1;i++) {
  317. if (pTransport != pOldTransports[i]) {
  318. pTransports[j] = pOldTransports[i];
  319. pLocalAddresses[j] = &pOldTransports[i]->RxCeAddress;
  320. j++;
  321. }
  322. }
  323. for(i=0;i<Count;i++)
  324. SmbCeReferenceTransport(pTransports[i]);
  325. pTransportArray->ReferenceCount = 1;
  326. pTransportArray->Count = Count;
  327. pTransportArray->SmbCeTransports = &pTransports[0];
  328. pTransportArray->LocalAddresses = &pLocalAddresses[0];
  329. }
  330. }
  331. if (Status == STATUS_SUCCESS) {
  332. // signal the CSC agent if this is the last transport
  333. SignalCscAgent = (pTransportArray == NULL);
  334. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  335. MRxSmbTransports.pTransportArray = pTransportArray;
  336. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  337. // Double dereferencing is necessary to ensure that
  338. // the old transport array is destroyed.
  339. SmbCeDereferenceTransportArray(pOldTransportArray);
  340. } else {
  341. if (pTransportArray != NULL) {
  342. RxFreePool(pTransportArray);
  343. }
  344. if (pTransports != NULL) {
  345. RxFreePool(pTransports);
  346. }
  347. if (pLocalAddresses != NULL) {
  348. RxFreePool(pLocalAddresses);
  349. }
  350. }
  351. }
  352. SmbCeDereferenceTransportArray(pOldTransportArray);
  353. }
  354. SmbCeReleaseResource();
  355. if (fReportRemovalToCSC)
  356. {
  357. MRxSmbCscSignalNetStatus(FALSE, SignalCscAgent);
  358. }
  359. SmbCeDiscardUnavailableServerList();
  360. return Status;
  361. }
  362. PSMBCE_TRANSPORT
  363. SmbCeFindTransport(
  364. PUNICODE_STRING pTransportName)
  365. /*++
  366. Routine Description:
  367. This routine maps a transport name to the appropriate
  368. PSMBCE_TRANSPORT instance
  369. Arguments:
  370. pTransportName - the transport name
  371. Return Value:
  372. a valid PSMBCE_TRANSPORT if one exists otherwise NULL
  373. Notes:
  374. --*/
  375. {
  376. KIRQL SavedIrql;
  377. PLIST_ENTRY pEntry;
  378. PSMBCE_TRANSPORT pTransport;
  379. BOOLEAN Found = FALSE;
  380. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  381. PAGED_CODE();
  382. pTransportArray = SmbCeReferenceTransportArray();
  383. if (pTransportArray == NULL) {
  384. RxDbgTrace(0, Dbg, ("SmbCeFindTransport : Transport not available.\n"));
  385. return NULL;
  386. }
  387. if (pTransportArray != NULL) {
  388. ULONG i;
  389. for (i=0;i<pTransportArray->Count;i++) {
  390. pTransport = pTransportArray->SmbCeTransports[i];
  391. if (RtlEqualUnicodeString(
  392. &pTransport->RxCeTransport.Name,
  393. pTransportName,
  394. TRUE)) {
  395. SmbCeReferenceTransport(pTransport);
  396. Found = TRUE;
  397. break;
  398. }
  399. }
  400. }
  401. if (!Found) {
  402. pTransport = NULL;
  403. }
  404. SmbCeDereferenceTransportArray(pTransportArray);
  405. return pTransport;
  406. }
  407. VOID
  408. SmbCepTearDownServerTransport(
  409. PSMBCEDB_SERVER_ENTRY pServerEntry)
  410. /*++
  411. Routine Description:
  412. This routine uninitializes the transport information corresponding to a server
  413. Arguments:
  414. pServerEntry - the server entry instance in the database
  415. Notes:
  416. --*/
  417. {
  418. NTSTATUS Status = STATUS_SUCCESS;
  419. SMBCEDB_SERVER_TYPE ServerType = SmbCeGetServerType(pServerEntry);
  420. BOOLEAN WaitForMailSlotTransportRundown = FALSE;
  421. BOOLEAN WaitForTransportRundown = FALSE;
  422. BOOLEAN TearDown = FALSE;
  423. SmbCeAcquireSpinLock();
  424. if (!pServerEntry->IsTransportDereferenced) {
  425. // ServerEntry takes only one reference count of transport, which should only be
  426. // dereferenced once when it comes to tear down transport. Multiple dereference called
  427. // from construct server transport and PNP unbind transport needs to be prevented.
  428. pServerEntry->IsTransportDereferenced = TRUE;
  429. TearDown = TRUE;
  430. KeInitializeEvent(&pServerEntry->MailSlotTransportRundownEvent,NotificationEvent,FALSE);
  431. KeInitializeEvent(&pServerEntry->TransportRundownEvent,NotificationEvent,FALSE);
  432. if (pServerEntry->pTransport != NULL) {
  433. pServerEntry->pTransport->State = SMBCEDB_MARKED_FOR_DELETION;
  434. pServerEntry->pTransport->pRundownEvent = &pServerEntry->TransportRundownEvent;
  435. WaitForTransportRundown = TRUE;
  436. }
  437. if (pServerEntry->pMailSlotTransport != NULL) {
  438. pServerEntry->pMailSlotTransport->State = SMBCEDB_MARKED_FOR_DELETION;
  439. pServerEntry->pMailSlotTransport->pRundownEvent = &pServerEntry->MailSlotTransportRundownEvent;
  440. WaitForMailSlotTransportRundown = TRUE;
  441. }
  442. } else {
  443. if (pServerEntry->pTransport != NULL) {
  444. WaitForTransportRundown = TRUE;
  445. }
  446. if (pServerEntry->pMailSlotTransport != NULL) {
  447. WaitForMailSlotTransportRundown = TRUE;
  448. }
  449. }
  450. SmbCeReleaseSpinLock();
  451. if (TearDown) {
  452. if (pServerEntry->pTransport != NULL) {
  453. SmbCeDereferenceServerTransport(&pServerEntry->pTransport);
  454. }
  455. if (pServerEntry->pMailSlotTransport != NULL) {
  456. SmbCeDereferenceServerTransport(&pServerEntry->pMailSlotTransport);
  457. }
  458. }
  459. if (WaitForTransportRundown) {
  460. KeWaitForSingleObject(
  461. &pServerEntry->TransportRundownEvent,
  462. Executive,
  463. KernelMode,
  464. FALSE,
  465. NULL );
  466. }
  467. if (WaitForMailSlotTransportRundown) {
  468. KeWaitForSingleObject(
  469. &pServerEntry->MailSlotTransportRundownEvent,
  470. Executive,
  471. KernelMode,
  472. FALSE,
  473. NULL );
  474. }
  475. }
  476. VOID
  477. SmbCeTearDownServerTransport(
  478. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  479. /*++
  480. Routine Description:
  481. This routine tears down the server transport instance
  482. Arguments:
  483. pContext - the server transport construction context
  484. Notes:
  485. --*/
  486. {
  487. SmbCepTearDownServerTransport(pContext->pServerEntry);
  488. if (pContext->pCompletionEvent != NULL) {
  489. ASSERT(pContext->pCallbackContext == NULL);
  490. ASSERT(pContext->pCompletionRoutine == NULL);
  491. KeSetEvent(
  492. pContext->pCompletionEvent,
  493. 0,
  494. FALSE );
  495. } else if (pContext->pCallbackContext != NULL) {
  496. ASSERT(pContext->pCompletionEvent == NULL);
  497. (pContext->pCompletionRoutine)(pContext->pCallbackContext);
  498. }
  499. RxFreePool(pContext);
  500. }
  501. VOID
  502. SmbCepUpdateTransportConstructionState(
  503. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  504. {
  505. SMBCE_SERVER_TRANSPORT_CONSTRUCTION_STATE State;
  506. if (pContext->Status == STATUS_SUCCESS) {
  507. if (pContext->TransportsToBeConstructed & SMBCE_STT_MAILSLOT) {
  508. pContext->TransportsToBeConstructed &= ~SMBCE_STT_MAILSLOT;
  509. State = SmbCeServerMailSlotTransportConstructionBegin;
  510. } else if (pContext->TransportsToBeConstructed & SMBCE_STT_VC) {
  511. pContext->TransportsToBeConstructed &= ~SMBCE_STT_VC;
  512. State = SmbCeServerVcTransportConstructionBegin;
  513. } else {
  514. State = SmbCeServerTransportConstructionEnd;
  515. }
  516. } else {
  517. State = SmbCeServerTransportConstructionEnd;
  518. }
  519. pContext->State = State;
  520. }
  521. VOID
  522. SmbCeConstructServerTransport(
  523. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  524. /*++
  525. Routine Description:
  526. This routine constructs the server transport instance
  527. Arguments:
  528. pContext - the server transport construction context
  529. Notes:
  530. --*/
  531. {
  532. NTSTATUS Status;
  533. PSMBCEDB_SERVER_ENTRY pServerEntry;
  534. SMBCEDB_SERVER_TYPE ServerType;
  535. BOOLEAN ContinueConstruction = TRUE;
  536. BOOLEAN UpdateUnavailableServerlist = TRUE;
  537. PAGED_CODE();
  538. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  539. pServerEntry = pContext->pServerEntry;
  540. ServerType = SmbCeGetServerType(pServerEntry);
  541. do {
  542. switch (pContext->State) {
  543. case SmbCeServerTransportConstructionBegin :
  544. {
  545. if ((pServerEntry->pTransport != NULL) ||
  546. (pServerEntry->pMailSlotTransport != NULL)) {
  547. SmbCepTearDownServerTransport(pServerEntry);
  548. }
  549. ASSERT((pServerEntry->pTransport == NULL) &&
  550. (pServerEntry->pMailSlotTransport == NULL));
  551. pContext->Status = STATUS_SUCCESS;
  552. // See if we have any reason to believe this server is unavailable
  553. pContext->Status = SmbCeIsServerAvailable( &pServerEntry->Name );
  554. if (pContext->Status != STATUS_SUCCESS) {
  555. UpdateUnavailableServerlist = FALSE;
  556. }
  557. SmbCepUpdateTransportConstructionState(pContext);
  558. }
  559. break;
  560. case SmbCeServerMailSlotTransportConstructionBegin:
  561. {
  562. Status = MsInstantiateServerTransport(
  563. pContext);
  564. if (Status == STATUS_PENDING) {
  565. ContinueConstruction = FALSE;
  566. break;
  567. }
  568. ASSERT(pContext->State == SmbCeServerMailSlotTransportConstructionEnd);
  569. }
  570. // lack of break intentional
  571. case SmbCeServerMailSlotTransportConstructionEnd:
  572. {
  573. SmbCepUpdateTransportConstructionState(pContext);
  574. }
  575. break;
  576. case SmbCeServerVcTransportConstructionBegin:
  577. {
  578. Status = VctInstantiateServerTransport(
  579. pContext);
  580. if (Status == STATUS_PENDING) {
  581. ContinueConstruction = FALSE;
  582. break;
  583. }
  584. ASSERT(pContext->State == SmbCeServerVcTransportConstructionEnd);
  585. }
  586. // lack of break intentional
  587. case SmbCeServerVcTransportConstructionEnd:
  588. {
  589. SmbCepUpdateTransportConstructionState(pContext);
  590. }
  591. break;
  592. case SmbCeServerTransportConstructionEnd:
  593. {
  594. pServerEntry->ServerStatus = pContext->Status;
  595. if (pServerEntry->ServerStatus == STATUS_SUCCESS) {
  596. SmbCeAcquireSpinLock();
  597. ASSERT(pContext->pMailSlotTransport != NULL);
  598. pContext->pMailSlotTransport->SwizzleCount = 1;
  599. if (pContext->pTransport != NULL) {
  600. pContext->pTransport->SwizzleCount = 1;
  601. }
  602. pServerEntry->pTransport = pContext->pTransport;
  603. pServerEntry->pMailSlotTransport = pContext->pMailSlotTransport;
  604. pContext->pTransport = NULL;
  605. pContext->pMailSlotTransport = NULL;
  606. if (pContext->pCallbackContext != NULL) {
  607. pContext->pCallbackContext->Status = STATUS_SUCCESS;
  608. }
  609. pServerEntry->IsTransportDereferenced = FALSE;
  610. pServerEntry->SecuritySignaturesActive = FALSE;
  611. pServerEntry->SecuritySignaturesEnabled = FALSE;
  612. SmbCeReleaseSpinLock();
  613. } else {
  614. PRX_CONTEXT pRxContext = NULL;
  615. if (UpdateUnavailableServerlist &&
  616. !pServerEntry->Server.IsRemoteBootServer &&
  617. (pServerEntry->PreferredTransport == NULL)) {
  618. // In remote boot or specific transport cases, we don't add it to
  619. // the list so that no negative caching is introduced.
  620. SmbCeServerIsUnavailable( &pServerEntry->Name, pServerEntry->ServerStatus );
  621. }
  622. if (pContext->pMailSlotTransport != NULL) {
  623. pContext->pMailSlotTransport->pDispatchVector->TearDown(
  624. pContext->pMailSlotTransport);
  625. }
  626. if (pContext->pTransport != NULL) {
  627. pContext->pTransport->pDispatchVector->TearDown(
  628. pContext->pTransport);
  629. }
  630. pContext->pTransport = NULL;
  631. pContext->pMailSlotTransport = NULL;
  632. pServerEntry->pTransport = NULL;
  633. pServerEntry->pMailSlotTransport = NULL;
  634. if ((pContext->pCallbackContext) &&
  635. (pContext->pCallbackContext->SrvCalldownStructure)) {
  636. pRxContext =
  637. pContext->pCallbackContext->SrvCalldownStructure->RxContext;
  638. }
  639. Status = CscTransitionServerEntryForDisconnectedOperation(
  640. pServerEntry,
  641. pRxContext,
  642. pServerEntry->ServerStatus,
  643. TRUE // to autodial or not to autodial
  644. );
  645. if (pContext->pCallbackContext != NULL) {
  646. pContext->pCallbackContext->Status = Status;
  647. }
  648. if (SmbCeIsServerInDisconnectedMode(pServerEntry)) {
  649. pServerEntry->ServerStatus = STATUS_SUCCESS;
  650. }
  651. else
  652. {
  653. pServerEntry->ServerStatus = Status;
  654. }
  655. }
  656. if (pContext->pCompletionEvent != NULL) {
  657. ASSERT(pContext->pCallbackContext == NULL);
  658. ASSERT(pContext->pCompletionRoutine == NULL);
  659. KeSetEvent(
  660. pContext->pCompletionEvent,
  661. 0,
  662. FALSE );
  663. } else if (pContext->pCallbackContext != NULL) {
  664. ASSERT(pContext->pCompletionEvent == NULL);
  665. (pContext->pCompletionRoutine)(pContext->pCallbackContext);
  666. } else {
  667. ASSERT(!"ill formed transport initialization context");
  668. }
  669. if (pContext->WorkQueueItem.List.Flink != NULL) {
  670. //DbgBreakPoint();
  671. }
  672. // pServerEntry->ConstructionContext = NULL;
  673. RxFreePool(pContext);
  674. ContinueConstruction = FALSE;
  675. }
  676. }
  677. } while (ContinueConstruction);
  678. }
  679. NTSTATUS
  680. SmbCepInitializeServerTransport(
  681. PSMBCEDB_SERVER_ENTRY pServerEntry,
  682. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CALLBACK pCallbackRoutine,
  683. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext,
  684. ULONG TransportsToBeConstructed)
  685. /*++
  686. Routine Description:
  687. This routine initializes the transport information corresponding to a server
  688. Arguments:
  689. pServerEntry - the server entry instance in the database
  690. pCallbackRoutine - the callback routine
  691. pCallbackContext - the callback context
  692. TransportsToBeConstructed -- the transports to be constructed
  693. Return Value:
  694. STATUS_SUCCESS - the server transport construction has been finalized.
  695. Other Status codes correspond to error situations.
  696. Notes:
  697. Currently, only connection oriented transports are handled.
  698. --*/
  699. {
  700. NTSTATUS Status;
  701. BOOLEAN CompleteConstruction;
  702. PAGED_CODE();
  703. if ((pServerEntry->ServerStatus == STATUS_SUCCESS) &&
  704. (pServerEntry->pTransport != NULL) &&
  705. (pServerEntry->pMailSlotTransport != NULL)) {
  706. Status = STATUS_SUCCESS;
  707. CompleteConstruction = TRUE;
  708. } else {
  709. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext;
  710. pContext = RxAllocatePoolWithTag(
  711. NonPagedPool,
  712. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT),
  713. MRXSMB_TRANSPORT_POOLTAG);
  714. CompleteConstruction = (pContext == NULL);
  715. if (pContext != NULL) {
  716. KEVENT CompletionEvent;
  717. RtlZeroMemory(
  718. pContext,
  719. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT));
  720. pContext->Status = STATUS_SUCCESS;
  721. pContext->pServerEntry = pServerEntry;
  722. pContext->State = SmbCeServerTransportConstructionBegin;
  723. pContext->TransportsToBeConstructed = TransportsToBeConstructed;
  724. if (pCallbackContext == NULL) {
  725. KeInitializeEvent(
  726. &CompletionEvent,
  727. NotificationEvent,
  728. FALSE);
  729. pContext->pCompletionEvent = &CompletionEvent;
  730. } else {
  731. pContext->pCallbackContext = pCallbackContext;
  732. pContext->pCompletionRoutine = pCallbackRoutine;
  733. }
  734. pServerEntry->ConstructionContext = (PVOID)pContext;
  735. Status = STATUS_PENDING;
  736. // always post to a worker thread. This is to avaoid the problem of
  737. // a thread in system process that is impersonating for a non-admin user
  738. // When this happens, the thread gets access denied while opening a transport
  739. // handle
  740. Status = RxPostToWorkerThread(
  741. MRxSmbDeviceObject,
  742. CriticalWorkQueue,
  743. &pContext->WorkQueueItem,
  744. SmbCeConstructServerTransport,
  745. pContext);
  746. if (Status == STATUS_SUCCESS) {
  747. Status = STATUS_PENDING;
  748. } else {
  749. pServerEntry->ConstructionContext = NULL;
  750. RxFreePool(pContext);
  751. CompleteConstruction = TRUE;
  752. }
  753. if ((Status == STATUS_PENDING) && (pCallbackContext == NULL)) {
  754. KeWaitForSingleObject(
  755. &CompletionEvent,
  756. Executive,
  757. KernelMode,
  758. FALSE,
  759. NULL );
  760. Status = pServerEntry->ServerStatus;
  761. }
  762. } else {
  763. Status = STATUS_INSUFFICIENT_RESOURCES;
  764. }
  765. }
  766. if (CompleteConstruction) {
  767. pServerEntry->ServerStatus = Status;
  768. if (pCallbackRoutine != NULL) {
  769. pCallbackContext->Status = Status;
  770. (pCallbackRoutine)(pCallbackContext);
  771. Status = STATUS_PENDING;
  772. }
  773. }
  774. return Status;
  775. }
  776. NTSTATUS
  777. SmbCeUninitializeServerTransport(
  778. PSMBCEDB_SERVER_ENTRY pServerEntry,
  779. PSMBCE_SERVER_TRANSPORT_DESTRUCTION_CALLBACK pCallbackRoutine,
  780. PVOID pCallbackContext)
  781. /*++
  782. Routine Description:
  783. This routine uninitializes the transport information corresponding to a server
  784. Arguments:
  785. pServerEntry - the server entry instance in the database
  786. Returns:
  787. STATUS_SUCCESS if successful
  788. Notes:
  789. Currently, only connection oriented transports are handled.
  790. In order to handle async. operations the uninitialization has to be coordinated
  791. with the referencing mechanism. It is for this reason that this routine sets up
  792. a rundown event and waits for it to be set.
  793. --*/
  794. {
  795. NTSTATUS Status = STATUS_SUCCESS;
  796. PAGED_CODE();
  797. if (pCallbackRoutine == NULL &&
  798. IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  799. SmbCepTearDownServerTransport(pServerEntry);
  800. } else {
  801. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext;
  802. pContext = RxAllocatePoolWithTag(
  803. NonPagedPool,
  804. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT),
  805. MRXSMB_TRANSPORT_POOLTAG);
  806. if (pContext != NULL) {
  807. KEVENT CompletionEvent;
  808. RtlZeroMemory(
  809. pContext,
  810. sizeof(SMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT));
  811. pContext->Status = STATUS_SUCCESS;
  812. pContext->pServerEntry = pServerEntry;
  813. if (pCallbackRoutine == NULL) {
  814. KeInitializeEvent(
  815. &CompletionEvent,
  816. NotificationEvent,
  817. FALSE);
  818. pContext->pCompletionEvent = &CompletionEvent;
  819. } else {
  820. pContext->pCallbackContext = pCallbackContext;
  821. pContext->pCompletionRoutine = pCallbackRoutine;
  822. }
  823. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  824. SmbCeTearDownServerTransport(pContext);
  825. } else {
  826. Status = RxPostToWorkerThread(
  827. MRxSmbDeviceObject,
  828. CriticalWorkQueue,
  829. &pContext->WorkQueueItem,
  830. SmbCeTearDownServerTransport,
  831. pContext);
  832. }
  833. if (Status == STATUS_SUCCESS) {
  834. if (pCallbackRoutine == NULL) {
  835. KeWaitForSingleObject(
  836. &CompletionEvent,
  837. Executive,
  838. KernelMode,
  839. FALSE,
  840. NULL );
  841. } else {
  842. Status = STATUS_PENDING;
  843. }
  844. } else {
  845. RxFreePool(pContext);
  846. }
  847. } else {
  848. Status = STATUS_INSUFFICIENT_RESOURCES;
  849. }
  850. }
  851. return Status;
  852. }
  853. VOID
  854. SmbCeCompleteUninitializeServerTransport(
  855. PSMBCEDB_SERVER_ENTRY pServerEntry)
  856. {
  857. // in case of async uninitialize server transport, an additional reference count of
  858. // server entry should be taken so that uninitialize server transport will not be
  859. // called once again from tear down server entry if its reference count comes to 0
  860. // before uninitialize server transport is done.
  861. SmbCeDereferenceServerEntry(pServerEntry);
  862. }
  863. NTSTATUS
  864. SmbCeInitiateDisconnect(
  865. PSMBCEDB_SERVER_ENTRY pServerEntry)
  866. /*++
  867. Routine Description:
  868. This routine initiates the TDI disconnect
  869. Arguments:
  870. pServerEntry - the server entry instance in the database
  871. Return Value:
  872. STATUS_SUCCESS - the server transport construction has been finalized.
  873. Other Status codes correspond to error situations.
  874. Notes:
  875. --*/
  876. {
  877. NTSTATUS Status;
  878. PSMBCE_SERVER_TRANSPORT pTransport;
  879. PSMBCE_SERVER_TRANSPORT pMailSlotTransport;
  880. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  881. Status = SmbCeReferenceServerTransport(&pServerEntry->pTransport);
  882. if (Status == STATUS_SUCCESS) {
  883. Status = (pServerEntry->pTransport->pDispatchVector->InitiateDisconnect)(
  884. pServerEntry->pTransport);
  885. if (Status != STATUS_SUCCESS) {
  886. RxDbgTrace(0, Dbg, ("SmbCeInitiateDisconnect : Status %lx\n",Status));
  887. }
  888. SmbCeDereferenceServerTransport(&pServerEntry->pTransport);
  889. }
  890. Status = SmbCeReferenceServerTransport(&pServerEntry->pMailSlotTransport);
  891. if (Status == STATUS_SUCCESS) {
  892. Status = (pServerEntry->pMailSlotTransport->pDispatchVector->InitiateDisconnect)(
  893. pServerEntry->pMailSlotTransport);
  894. if (Status != STATUS_SUCCESS) {
  895. RxDbgTrace(0, Dbg, ("SmbCeInitiateDisconnect MS : Status %lx\n",Status));
  896. }
  897. SmbCeDereferenceServerTransport(&pServerEntry->pMailSlotTransport);
  898. }
  899. return STATUS_SUCCESS;
  900. }
  901. LONG Initializes[SENTINEL_EXCHANGE] = {0,0,0,0,0};
  902. LONG Uninitializes[SENTINEL_EXCHANGE] = {0,0,0,0,0};
  903. NTSTATUS
  904. SmbCeInitializeExchangeTransport(
  905. PSMB_EXCHANGE pExchange)
  906. /*++
  907. Routine Description:
  908. This routine initializes the transport associated with the exchange
  909. Arguments:
  910. pExchange - the exchange to be initialized
  911. Return Value:
  912. STATUS_SUCCESS - the exchange transport initialization has been finalized.
  913. Other Status codes correspond to error situations.
  914. Notes:
  915. --*/
  916. {
  917. NTSTATUS Status;
  918. PSMBCEDB_SERVER_ENTRY pServerEntry;
  919. PAGED_CODE();
  920. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  921. Status = pExchange->SmbStatus;
  922. if (Status == STATUS_SUCCESS) {
  923. PSMBCE_SERVER_TRANSPORT *pTransportPointer;
  924. if (FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
  925. pTransportPointer = &pServerEntry->pMailSlotTransport;
  926. } else {
  927. pTransportPointer = &pServerEntry->pTransport;
  928. }
  929. if (*pTransportPointer != NULL) {
  930. Status = SmbCeReferenceServerTransport(pTransportPointer);
  931. if (Status == STATUS_SUCCESS) {
  932. Status = ((*pTransportPointer)->pDispatchVector->InitializeExchange)(
  933. *pTransportPointer,
  934. pExchange);
  935. if (Status == STATUS_SUCCESS) {
  936. ULONG TransportInitialized;
  937. InterlockedIncrement(&Initializes[pExchange->Type]);
  938. TransportInitialized = InterlockedExchange(&pExchange->ExchangeTransportInitialized,1);
  939. ASSERT(TransportInitialized == 0);
  940. } else {
  941. SmbCeDereferenceServerTransport(pTransportPointer);
  942. }
  943. }
  944. } else {
  945. Status = STATUS_CONNECTION_DISCONNECTED;
  946. }
  947. }
  948. return Status;
  949. }
  950. NTSTATUS
  951. SmbCeUninitializeExchangeTransport(
  952. PSMB_EXCHANGE pExchange)
  953. /*++
  954. Routine Description:
  955. This routine uniinitializes the transport associated with the exchange
  956. Arguments:
  957. pExchange - the exchange to be initialized
  958. Return Value:
  959. STATUS_SUCCESS - the exchange transport initialization has been finalized.
  960. Other Status codes correspond to error situations.
  961. Notes:
  962. --*/
  963. {
  964. NTSTATUS Status;
  965. PSMBCEDB_SERVER_ENTRY pServerEntry;
  966. PAGED_CODE();
  967. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  968. if (InterlockedExchange(&pExchange->ExchangeTransportInitialized,0)==1) {
  969. PSMBCE_SERVER_TRANSPORT *pTransportPointer;
  970. if (FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
  971. pTransportPointer = &pServerEntry->pMailSlotTransport;
  972. } else {
  973. pTransportPointer = &pServerEntry->pTransport;
  974. }
  975. if (*pTransportPointer != NULL) {
  976. Status = ((*pTransportPointer)->pDispatchVector->UninitializeExchange)(
  977. *pTransportPointer,
  978. pExchange);
  979. SmbCeDereferenceServerTransport(pTransportPointer);
  980. InterlockedIncrement(&Uninitializes[pExchange->Type]);
  981. return Status;
  982. } else {
  983. return STATUS_CONNECTION_DISCONNECTED;
  984. }
  985. } else {
  986. return pExchange->SmbStatus;
  987. }
  988. }
  989. NTSTATUS
  990. SmbCepReferenceServerTransport(
  991. PSMBCE_SERVER_TRANSPORT *pServerTransportPointer)
  992. /*++
  993. Routine Description:
  994. This routine references the transport associated with a server entry
  995. Arguments:
  996. pServerEntry - the server entry instance in the database
  997. Return Value:
  998. STATUS_SUCCESS - the server transport was successfully referenced
  999. Other Status codes correspond to error situations.
  1000. Notes:
  1001. --*/
  1002. {
  1003. NTSTATUS Status = STATUS_SUCCESS;
  1004. SmbCeAcquireSpinLock();
  1005. if (*pServerTransportPointer != NULL &&
  1006. (*pServerTransportPointer)->State == SMBCEDB_ACTIVE) {
  1007. InterlockedIncrement(&(*pServerTransportPointer)->SwizzleCount);
  1008. Status = STATUS_SUCCESS;
  1009. } else {
  1010. Status = STATUS_CONNECTION_DISCONNECTED;
  1011. }
  1012. SmbCeReleaseSpinLock();
  1013. return Status;
  1014. }
  1015. NTSTATUS
  1016. SmbCepDereferenceServerTransport(
  1017. PSMBCE_SERVER_TRANSPORT *pServerTransportPointer)
  1018. /*++
  1019. Routine Description:
  1020. This routine dereferences the transport associated with a server entry
  1021. Arguments:
  1022. pServerTransportPointer - the server entry transport instance pointer
  1023. Return Value:
  1024. STATUS_SUCCESS - the server transport was successfully dereferenced
  1025. Other Status codes correspond to error situations.
  1026. Notes:
  1027. On finalization this routine sets the event to enable the process awaiting
  1028. tear down to restart. It also tears down the associated server transport
  1029. instance.
  1030. As a side effect the pointer value is set to NULL under the protection of a
  1031. spin lock.
  1032. --*/
  1033. {
  1034. NTSTATUS Status = STATUS_SUCCESS;
  1035. SmbCeAcquireSpinLock();
  1036. if (*pServerTransportPointer != NULL) {
  1037. LONG FinalRefCount;
  1038. PKEVENT pRundownEvent;
  1039. PSMBCE_SERVER_TRANSPORT pServerTransport;
  1040. pServerTransport = *pServerTransportPointer;
  1041. FinalRefCount = InterlockedDecrement(&pServerTransport->SwizzleCount);
  1042. if (FinalRefCount == 0) {
  1043. pServerTransport->State = SMBCEDB_INVALID;
  1044. // transport is set to NULL before the spinlock is release so that no
  1045. // exchange should reference it after it's been torn down
  1046. *pServerTransportPointer = NULL;
  1047. pRundownEvent = pServerTransport->pRundownEvent;
  1048. }
  1049. SmbCeReleaseSpinLock();
  1050. if (FinalRefCount == 0) {
  1051. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1052. pServerTransport->pDispatchVector->TearDown(pServerTransport);
  1053. } else {
  1054. Status = RxDispatchToWorkerThread(
  1055. MRxSmbDeviceObject,
  1056. CriticalWorkQueue,
  1057. pServerTransport->pDispatchVector->TearDown,
  1058. pServerTransport);
  1059. }
  1060. }
  1061. } else {
  1062. SmbCeReleaseSpinLock();
  1063. Status = STATUS_CONNECTION_DISCONNECTED;
  1064. }
  1065. return Status;
  1066. }
  1067. NTSTATUS
  1068. SmbCepReferenceTransport(
  1069. PSMBCE_TRANSPORT pTransport)
  1070. /*++
  1071. Routine Description:
  1072. This routine references the transport instance
  1073. Arguments:
  1074. pTransport - the transport instance
  1075. Return Value:
  1076. STATUS_SUCCESS - the server transport was successfully referenced
  1077. Other Status codes correspond to error situations.
  1078. Notes:
  1079. --*/
  1080. {
  1081. NTSTATUS Status = STATUS_SUCCESS;
  1082. if (pTransport != NULL) {
  1083. SmbCeAcquireSpinLock();
  1084. if (pTransport->Active) {
  1085. InterlockedIncrement(&pTransport->SwizzleCount);
  1086. Status = STATUS_SUCCESS;
  1087. } else {
  1088. Status = STATUS_UNSUCCESSFUL;
  1089. }
  1090. SmbCeReleaseSpinLock();
  1091. } else {
  1092. Status = STATUS_INVALID_PARAMETER;
  1093. }
  1094. return Status;
  1095. }
  1096. NTSTATUS
  1097. SmbCepDereferenceTransport(
  1098. PSMBCE_TRANSPORT pTransport)
  1099. /*++
  1100. Routine Description:
  1101. This routine dereferences the transport
  1102. Arguments:
  1103. pTransport - the transport instance
  1104. Return Value:
  1105. STATUS_SUCCESS - the server transport was successfully dereferenced
  1106. Other Status codes correspond to error situations.
  1107. Notes:
  1108. --*/
  1109. {
  1110. NTSTATUS Status = STATUS_SUCCESS;
  1111. BOOLEAN AttachToSystemProcess = FALSE;
  1112. KAPC_STATE ApcState;
  1113. PAGED_CODE();
  1114. if (pTransport != NULL) {
  1115. LONG FinalRefCount;
  1116. FinalRefCount = InterlockedDecrement(&pTransport->SwizzleCount);
  1117. if (FinalRefCount == 0) {
  1118. SmbCeRemoveTransport(pTransport);
  1119. if (IoGetCurrentProcess() != RxGetRDBSSProcess()) {
  1120. KeStackAttachProcess(RxGetRDBSSProcess(),&ApcState);
  1121. AttachToSystemProcess = TRUE;
  1122. }
  1123. RxCeTearDownAddress(&pTransport->RxCeAddress);
  1124. RxCeTearDownTransport(&pTransport->RxCeTransport);
  1125. if (AttachToSystemProcess) {
  1126. KeUnstackDetachProcess(&ApcState);
  1127. }
  1128. RxFreePool(pTransport);
  1129. }
  1130. } else {
  1131. Status = STATUS_INVALID_PARAMETER;
  1132. }
  1133. return Status;
  1134. }
  1135. #ifndef MRXSMB_PNP_POWER5
  1136. HANDLE MRxSmbTdiNotificationHandle = NULL;
  1137. VOID
  1138. MRxSmbpBindTransportCallback(
  1139. IN PUNICODE_STRING pTransportName
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. TDI calls this routine whenever a transport creates a new device object.
  1144. Arguments:
  1145. DeviceName - the name of the newly created device object
  1146. --*/
  1147. {
  1148. NTSTATUS Status = STATUS_SUCCESS;
  1149. PSMBCE_TRANSPORT pTransport;
  1150. PRXCE_TRANSPORT_PROVIDER_INFO pProviderInfo;
  1151. ULONG Priority;
  1152. BOOLEAN fBindToTransport = FALSE;
  1153. PAGED_CODE();
  1154. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1155. // if this is one of the transports that is of interest to the SMB
  1156. // mini rdr then register the address with it, otherwise skip it.
  1157. if (SmbCeContext.Transports.Length != 0) {
  1158. PWSTR pSmbMRxTransports = (PWSTR)SmbCeContext.Transports.Buffer;
  1159. UNICODE_STRING SmbMRxTransport;
  1160. Priority = 1;
  1161. while (*pSmbMRxTransports) {
  1162. SmbMRxTransport.Length = wcslen(pSmbMRxTransports) * sizeof(WCHAR);
  1163. if (SmbMRxTransport.Length == pTransportName->Length) {
  1164. SmbMRxTransport.MaximumLength = SmbMRxTransport.Length;
  1165. SmbMRxTransport.Buffer = pSmbMRxTransports;
  1166. if (RtlCompareUnicodeString(
  1167. &SmbMRxTransport,
  1168. pTransportName,
  1169. TRUE) == 0) {
  1170. fBindToTransport = TRUE;
  1171. break;
  1172. }
  1173. }
  1174. pSmbMRxTransports += (SmbMRxTransport.Length / sizeof(WCHAR) + 1);
  1175. Priority++;
  1176. }
  1177. }
  1178. if (!fBindToTransport) {
  1179. return;
  1180. }
  1181. pTransport = RxAllocatePoolWithTag(
  1182. NonPagedPool,
  1183. sizeof(SMBCE_TRANSPORT),
  1184. MRXSMB_TRANSPORT_POOLTAG);
  1185. if (pTransport != NULL) {
  1186. Status = RxCeBuildTransport(
  1187. &pTransport->RxCeTransport,
  1188. pTransportName,
  1189. 0xffff);
  1190. if (Status == STATUS_SUCCESS) {
  1191. PRXCE_TRANSPORT_PROVIDER_INFO pProviderInfo;
  1192. pProviderInfo = pTransport->RxCeTransport.pProviderInfo;
  1193. if (!(pProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) ||
  1194. !(pProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY)) {
  1195. RxCeTearDownTransport(
  1196. &pTransport->RxCeTransport);
  1197. Status = STATUS_PROTOCOL_UNREACHABLE;
  1198. RxFreePool(pTransport);
  1199. }
  1200. }
  1201. } else {
  1202. Status = STATUS_INSUFFICIENT_RESOURCES;
  1203. }
  1204. if (Status == STATUS_SUCCESS) {
  1205. // The connection capabilities match the capabilities required by the
  1206. // SMB mini redirector. Attempt to register the local address with the
  1207. // transport and if successful update the local transport list to include
  1208. // this transport for future connection considerations.
  1209. OEM_STRING OemServerName;
  1210. CHAR TransportAddressBuffer[TDI_TRANSPORT_ADDRESS_LENGTH +
  1211. TDI_ADDRESS_LENGTH_NETBIOS];
  1212. PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)TransportAddressBuffer;
  1213. PTDI_ADDRESS_NETBIOS pNetbiosAddress = (PTDI_ADDRESS_NETBIOS)pTransportAddress->Address[0].Address;
  1214. pTransportAddress->TAAddressCount = 1;
  1215. pTransportAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
  1216. pTransportAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1217. pNetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1218. OemServerName.MaximumLength = NETBIOS_NAME_LEN;
  1219. OemServerName.Buffer = pNetbiosAddress->NetbiosName;
  1220. Status = RtlUpcaseUnicodeStringToOemString(
  1221. &OemServerName,
  1222. &SmbCeContext.ComputerName,
  1223. FALSE);
  1224. if (NT_SUCCESS(Status)) {
  1225. // Ensure that the name is always of the desired length by padding
  1226. // white space to the end.
  1227. RtlCopyMemory(
  1228. &OemServerName.Buffer[OemServerName.Length],
  1229. " ",
  1230. NETBIOS_NAME_LEN - OemServerName.Length);
  1231. OemServerName.Buffer[NETBIOS_NAME_LEN - 1] = '\0';
  1232. // Register the Transport address for this mini redirector with the connection
  1233. // engine.
  1234. Status = RxCeBuildAddress(
  1235. &pTransport->RxCeAddress,
  1236. &pTransport->RxCeTransport,
  1237. pTransportAddress,
  1238. &MRxSmbVctAddressEventHandler,
  1239. &SmbCeContext);
  1240. if (Status == STATUS_SUCCESS) {
  1241. RxDbgTrace( 0, Dbg, ("MRxSmbTransportUpdateHandler: Adding new transport\n"));
  1242. pTransport->Active = TRUE;
  1243. pTransport->Priority = Priority;
  1244. pTransport->SwizzleCount = 0;
  1245. pTransport->ObjectCategory = SMB_SERVER_TRANSPORT_CATEGORY;
  1246. pTransport->ObjectType = SMBCEDB_OT_TRANSPORT;
  1247. pTransport->State = 0;
  1248. pTransport->Flags = 0;
  1249. // notify the browser about the transport
  1250. Status = SmbCePnpBindBrowser(pTransportName, TRUE);
  1251. // Add the transport to the list of transports
  1252. if (Status == STATUS_SUCCESS) {
  1253. SmbCeAddTransport(pTransport);
  1254. } else {
  1255. RxCeTearDownAddress(&pTransport->RxCeAddress);
  1256. MRxSmbLogTransportError(pTransportName,
  1257. &SmbCeContext.DomainName,
  1258. Status,
  1259. EVENT_RDR_CANT_BIND_TRANSPORT);
  1260. SmbLogError(Status,
  1261. LOG,
  1262. MRxSmbpBindTransportCallback_1,
  1263. LOGULONG(Status)
  1264. LOGUSTR(*pTransportName));
  1265. }
  1266. } else {
  1267. RxDbgTrace( 0, Dbg, ("MRxSmbTransportUpdateHandler: Address registration failed %lx\n",Status));
  1268. MRxSmbLogTransportError(pTransportName,
  1269. &SmbCeContext.DomainName,
  1270. Status,
  1271. EVENT_RDR_CANT_REGISTER_ADDRESS);
  1272. SmbLogError(Status,
  1273. LOG,
  1274. MRxSmbpBindTransportCallback_2,
  1275. LOGUSTR(*pTransportName));
  1276. }
  1277. }
  1278. if (Status != STATUS_SUCCESS) {
  1279. RxCeTearDownTransport(
  1280. &pTransport->RxCeTransport);
  1281. Status = STATUS_PROTOCOL_UNREACHABLE;
  1282. RxFreePool(pTransport);
  1283. }
  1284. }
  1285. }
  1286. VOID
  1287. MRxSmbpBindTransportWorkerThreadRoutine(
  1288. IN PUNICODE_STRING pTransportName)
  1289. {
  1290. PAGED_CODE();
  1291. MRxSmbpBindTransportCallback(pTransportName);
  1292. RxFreePool(pTransportName);
  1293. }
  1294. VOID
  1295. MRxSmbBindTransportCallback(
  1296. IN PUNICODE_STRING pTransportName
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. TDI calls this routine whenever a transport creates a device object
  1301. Arguments:
  1302. TransportName = the name of the deleted device object
  1303. --*/
  1304. {
  1305. PAGED_CODE();
  1306. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1307. MRxSmbpBindTransportCallback(pTransportName);
  1308. } else {
  1309. PUNICODE_STRING pNewTransportName;
  1310. NTSTATUS Status;
  1311. pNewTransportName = RxAllocatePoolWithTag(
  1312. PagedPool,
  1313. sizeof(UNICODE_STRING) + pTransportName->Length,
  1314. MRXSMB_TRANSPORT_POOLTAG);
  1315. if (pNewTransportName != NULL) {
  1316. pNewTransportName->MaximumLength = pTransportName->MaximumLength;
  1317. pNewTransportName->Length = pTransportName->Length;
  1318. pNewTransportName->Buffer = (PWCHAR)((PBYTE)pNewTransportName +
  1319. sizeof(UNICODE_STRING));
  1320. RtlCopyMemory(
  1321. pNewTransportName->Buffer,
  1322. pTransportName->Buffer,
  1323. pNewTransportName->Length);
  1324. Status = RxDispatchToWorkerThread(
  1325. MRxSmbDeviceObject,
  1326. CriticalWorkQueue,
  1327. MRxSmbpBindTransportWorkerThreadRoutine,
  1328. pNewTransportName);
  1329. } else {
  1330. Status = STATUS_INSUFFICIENT_RESOURCES;
  1331. }
  1332. if (Status != RX_MAP_STATUS(SUCCESS)) {
  1333. RxLog(("SmbCe Tdi Bind .Error %lx\n", Status));
  1334. MRxSmbLogTransportError(pTransportName,
  1335. &SmbCeContext.DomainName,
  1336. Status,
  1337. EVENT_RDR_CANT_BIND_TRANSPORT);
  1338. }
  1339. }
  1340. }
  1341. VOID
  1342. MRxSmbUnbindTransportCallback(
  1343. IN PUNICODE_STRING pTransportName
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. TDI calls this routine whenever a transport deletes a device object
  1348. Arguments:
  1349. TransportName = the name of the deleted device object
  1350. --*/
  1351. {
  1352. PSMBCE_TRANSPORT pTransport;
  1353. PAGED_CODE();
  1354. pTransport = SmbCeFindTransport(pTransportName);
  1355. if (pTransport != NULL) {
  1356. // notify the browser about the transport
  1357. SmbCePnpBindBrowser(pTransportName, FALSE);
  1358. // Remove this transport from the list of transports under consideration
  1359. // in the mini redirector.
  1360. SmbCeRemoveTransport(pTransport);
  1361. // Enumerate the servers and mark those servers utilizing this transport
  1362. // as having an invalid transport.
  1363. SmbCeHandleTransportInvalidation(pTransport);
  1364. // dereference the transport
  1365. SmbCeDereferenceTransport(pTransport);
  1366. }
  1367. }
  1368. NTSTATUS
  1369. MRxSmbRegisterForPnpNotifications()
  1370. /*++
  1371. Routine Description:
  1372. This routine registers with TDI for receiving transport notifications
  1373. --*/
  1374. {
  1375. NTSTATUS Status = STATUS_SUCCESS;
  1376. PAGED_CODE();
  1377. if(MRxSmbTdiNotificationHandle == NULL ) {
  1378. Status = TdiRegisterNotificationHandler (
  1379. MRxSmbBindTransportCallback,
  1380. MRxSmbUnbindTransportCallback,
  1381. &MRxSmbTdiNotificationHandle );
  1382. }
  1383. return Status;
  1384. }
  1385. NTSTATUS
  1386. MRxSmbDeregisterForPnpNotifications()
  1387. /*++
  1388. Routine Description:
  1389. This routine deregisters the TDI notification mechanism
  1390. Notes:
  1391. --*/
  1392. {
  1393. NTSTATUS Status = STATUS_SUCCESS;
  1394. PAGED_CODE();
  1395. if( MRxSmbTdiNotificationHandle != NULL ) {
  1396. Status = TdiDeregisterNotificationHandler( MRxSmbTdiNotificationHandle );
  1397. if( NT_SUCCESS( Status ) ) {
  1398. MRxSmbTdiNotificationHandle = NULL;
  1399. }
  1400. }
  1401. return Status;
  1402. }
  1403. #else
  1404. HANDLE MRxSmbTdiNotificationHandle = NULL;
  1405. KEVENT TdiNetStartupCompletionEvent;
  1406. LONG TdiBindRequestsActive = 0;
  1407. BOOLEAN TdiPnpNetReadyEventReceived = FALSE;
  1408. // The TRANSPORT_BIND_CONTEXT contains the result of the priority determination
  1409. // as well as the name. The priority is used to order the transports in the order
  1410. // in which connection attempts will be made
  1411. typedef struct _TRANSPORT_BIND_CONTEXT_ {
  1412. ULONG Priority;
  1413. UNICODE_STRING TransportName;
  1414. } TRANSPORT_BIND_CONTEXT, *PTRANSPORT_BIND_CONTEXT;
  1415. VOID
  1416. SmbCeSignalNetReadyEvent()
  1417. /*++
  1418. Routine Description:
  1419. The routine signals the net ready event if all the bind requests
  1420. have been completed and if the net ready event has been received from TDI
  1421. Arguments:
  1422. --*/
  1423. {
  1424. BOOLEAN SignalNetReadyEvent = FALSE;
  1425. SmbCeAcquireSpinLock();
  1426. if (TdiPnpNetReadyEventReceived &&
  1427. TdiBindRequestsActive == 0) {
  1428. SignalNetReadyEvent = TRUE;
  1429. }
  1430. SmbCeReleaseSpinLock();
  1431. if (SignalNetReadyEvent) {
  1432. KeSetEvent(
  1433. &TdiNetStartupCompletionEvent,
  1434. IO_NETWORK_INCREMENT,
  1435. FALSE);
  1436. }
  1437. }
  1438. VOID
  1439. MRxSmbpBindTransportCallback(
  1440. IN PTRANSPORT_BIND_CONTEXT pTransportContext)
  1441. /*++
  1442. Routine Description:
  1443. TDI calls this routine whenever a transport creates a new device object.
  1444. Arguments:
  1445. TransportName - the name of the newly created device object
  1446. TransportBindings - the transport bindings ( multi sz)
  1447. --*/
  1448. {
  1449. NTSTATUS Status = STATUS_SUCCESS;
  1450. PSMBCE_TRANSPORT pTransport;
  1451. PRXCE_TRANSPORT_PROVIDER_INFO pProviderInfo;
  1452. PUNICODE_STRING pTransportName;
  1453. PAGED_CODE();
  1454. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1455. pTransportName = &pTransportContext->TransportName;
  1456. RxDbgTrace( 0, Dbg, ("MrxSmbpBindTransportCallback, Transport Name = %wZ\n", pTransportName ));
  1457. pTransport = RxAllocatePoolWithTag(
  1458. NonPagedPool,
  1459. sizeof(SMBCE_TRANSPORT),
  1460. MRXSMB_TRANSPORT_POOLTAG);
  1461. if (pTransport != NULL) {
  1462. Status = RxCeBuildTransport(
  1463. &pTransport->RxCeTransport,
  1464. pTransportName,
  1465. 0xffff);
  1466. if (Status == STATUS_SUCCESS) {
  1467. PRXCE_TRANSPORT_PROVIDER_INFO pProviderInfo;
  1468. pProviderInfo = pTransport->RxCeTransport.pProviderInfo;
  1469. if (!(pProviderInfo->ServiceFlags & TDI_SERVICE_CONNECTION_MODE) ||
  1470. !(pProviderInfo->ServiceFlags & TDI_SERVICE_ERROR_FREE_DELIVERY)) {
  1471. RxCeTearDownTransport(
  1472. &pTransport->RxCeTransport);
  1473. Status = STATUS_PROTOCOL_UNREACHABLE;
  1474. RxFreePool(pTransport);
  1475. }
  1476. }
  1477. } else {
  1478. Status = STATUS_INSUFFICIENT_RESOURCES;
  1479. }
  1480. if (Status == STATUS_SUCCESS) {
  1481. // The connection capabilities match the capabilities required by the
  1482. // SMB mini redirector. Attempt to register the local address with the
  1483. // transport and if successful update the local transport list to include
  1484. // this transport for future connection considerations.
  1485. OEM_STRING OemServerName;
  1486. CHAR TransportAddressBuffer[TDI_TRANSPORT_ADDRESS_LENGTH +
  1487. TDI_ADDRESS_LENGTH_NETBIOS];
  1488. PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)TransportAddressBuffer;
  1489. PTDI_ADDRESS_NETBIOS pNetbiosAddress = (PTDI_ADDRESS_NETBIOS)pTransportAddress->Address[0].Address;
  1490. pTransportAddress->TAAddressCount = 1;
  1491. pTransportAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
  1492. pTransportAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1493. pNetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1494. OemServerName.MaximumLength = NETBIOS_NAME_LEN;
  1495. OemServerName.Buffer = pNetbiosAddress->NetbiosName;
  1496. Status = RtlUpcaseUnicodeStringToOemString(
  1497. &OemServerName,
  1498. &SmbCeContext.ComputerName,
  1499. FALSE);
  1500. if (NT_SUCCESS(Status)) {
  1501. // Ensure that the name is always of the desired length by padding
  1502. // white space to the end.
  1503. RtlCopyMemory(
  1504. &OemServerName.Buffer[OemServerName.Length],
  1505. " ",
  1506. NETBIOS_NAME_LEN - OemServerName.Length);
  1507. OemServerName.Buffer[NETBIOS_NAME_LEN - 1] = '\0';
  1508. // Register the Transport address for this mini redirector with the connection
  1509. // engine.
  1510. Status = RxCeBuildAddress(
  1511. &pTransport->RxCeAddress,
  1512. &pTransport->RxCeTransport,
  1513. pTransportAddress,
  1514. &MRxSmbVctAddressEventHandler,
  1515. &SmbCeContext);
  1516. if (Status == STATUS_SUCCESS) {
  1517. RxDbgTrace( 0, Dbg, ("MRxSmbTransportUpdateHandler: Adding new transport\n"));
  1518. pTransport->Active = TRUE;
  1519. pTransport->Priority = pTransportContext->Priority;
  1520. pTransport->SwizzleCount = 0;
  1521. pTransport->ObjectCategory = SMB_SERVER_TRANSPORT_CATEGORY;
  1522. pTransport->ObjectType = SMBCEDB_OT_TRANSPORT;
  1523. pTransport->State = 0;
  1524. pTransport->Flags = 0;
  1525. // notify the browser about the transport
  1526. Status = SmbCePnpBindBrowser(pTransportName, TRUE);
  1527. if (MRxSmbBootedRemotely && (Status == STATUS_REDIRECTOR_NOT_STARTED)) {
  1528. //
  1529. // Ignore failures here, because when starting during
  1530. // textmode setup in remote boot, the browser is not around.
  1531. //
  1532. Status = STATUS_SUCCESS;
  1533. }
  1534. // Add the transport to the list of transports
  1535. if (Status == STATUS_SUCCESS) {
  1536. SmbCeAddTransport(pTransport);
  1537. RxDbgTrace( 0, Dbg, ("MrxSmbpBindTransportCallback, Transport %wZ added\n", pTransportName ));
  1538. } else {
  1539. RxCeTearDownAddress(&pTransport->RxCeAddress);
  1540. MRxSmbLogTransportError(pTransportName,
  1541. &SmbCeContext.DomainName,
  1542. Status,
  1543. EVENT_RDR_CANT_BIND_TRANSPORT);
  1544. SmbLogError(Status,
  1545. LOG,
  1546. MRxSmbpBindTransportCallback_1,
  1547. LOGULONG(Status)
  1548. LOGUSTR(*pTransportName));
  1549. }
  1550. } else {
  1551. RxDbgTrace( 0, Dbg, ("MRxSmbTransportUpdateHandler: Address registration failed %lx\n",Status));
  1552. MRxSmbLogTransportError(pTransportName,
  1553. &SmbCeContext.DomainName,
  1554. Status,
  1555. EVENT_RDR_CANT_REGISTER_ADDRESS);
  1556. SmbLogError(Status,
  1557. LOG,
  1558. MRxSmbpBindTransportCallback_2,
  1559. LOGULONG(Status)
  1560. LOGUSTR(*pTransportName));
  1561. }
  1562. }
  1563. if (Status != STATUS_SUCCESS) {
  1564. RxDbgTrace( 0, Dbg, ("MrxSmbpBindTransportCallback, Transport %wZ unreachable 0x%x\n",
  1565. pTransportName, Status ));
  1566. RxCeTearDownTransport(
  1567. &pTransport->RxCeTransport);
  1568. Status = STATUS_PROTOCOL_UNREACHABLE;
  1569. RxFreePool(pTransport);
  1570. }
  1571. }
  1572. InterlockedDecrement(&TdiBindRequestsActive);
  1573. SmbCeSignalNetReadyEvent();
  1574. }
  1575. VOID
  1576. MRxSmbpBindTransportWorkerThreadRoutine(
  1577. IN PTRANSPORT_BIND_CONTEXT pTransportContext)
  1578. /*++
  1579. Routine Description:
  1580. The TDI callbacks always do not occur in the context of the FSP process.
  1581. Since there are a few TDi interfaces that accept handles we need to ensure
  1582. that such calls always gets funnelled back to the FSP.
  1583. Arguments:
  1584. pTransportContext - the transport binding context
  1585. --*/
  1586. {
  1587. PAGED_CODE();
  1588. MRxSmbpBindTransportCallback(pTransportContext);
  1589. RxFreePool(pTransportContext);
  1590. }
  1591. VOID
  1592. MRxSmbpUnbindTransportCallback(
  1593. PSMBCE_TRANSPORT pTransport)
  1594. /*++
  1595. Routine Description:
  1596. The Unbind callback routine which is always executed in the context of the
  1597. RDR process so that handles can be closed correctly
  1598. Arguments:
  1599. pTransport - the transport for which the PNP_OP_DEL was received
  1600. Notes:
  1601. On entry to this routine the appropriate transport must have been referenced
  1602. This routine will dereference it and invalidate the existing exchanges using
  1603. this transport.
  1604. --*/
  1605. {
  1606. PAGED_CODE();
  1607. // notify the browser about the transport
  1608. SmbCePnpBindBrowser(&pTransport->RxCeTransport.Name, FALSE);
  1609. // Remove this transport from the list of transports under consideration
  1610. // in the mini redirector.
  1611. SmbCeRemoveTransport(pTransport);
  1612. // Enumerate the servers and mark those servers utilizing this transport
  1613. // as having an invalid transport.
  1614. SmbCeHandleTransportInvalidation(pTransport);
  1615. // dereference the transport
  1616. SmbCeDereferenceTransport(pTransport);
  1617. }
  1618. VOID
  1619. MRxSmbpOverrideBindingPriority(
  1620. PUNICODE_STRING pTransportName,
  1621. PULONG pPriority
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. This function obtains a overriding priority value from the registry for a given
  1626. transport.
  1627. The priority of a transport controls the order in which connections are accepted. It is
  1628. sometimes useful for a customer to control which transport is used first in the redirector.
  1629. The priority is usually determined by the order of the transports in the binding list. With
  1630. the new Connections UI model for network setup, it will no longer be possible to adjust
  1631. the order of the bindings in the binding list. Thus, another mechanism is needed when the
  1632. user wants to override the priority assigned to a given binding.
  1633. Arguments:
  1634. pTransportName - pointer to UNICODE_STRING descriptor for transport string, for example
  1635. "\Device\Netbt_tcpip_{guid}"
  1636. pPriority - pointer to LONG to receive new priority on success, otherwise not touched
  1637. Return Value:
  1638. None
  1639. --*/
  1640. {
  1641. WCHAR valueBuffer[128];
  1642. UNICODE_STRING path, value, key;
  1643. USHORT length,ulength;
  1644. OBJECT_ATTRIBUTES objectAttributes;
  1645. NTSTATUS status;
  1646. HANDLE parametersHandle;
  1647. ULONG temp;
  1648. PAGED_CODE();
  1649. // Validate input
  1650. if (pTransportName->Length == 0) {
  1651. return;
  1652. }
  1653. // Open parameters key
  1654. RtlInitUnicodeString( &path, SMBMRX_MINIRDR_PARAMETERS );
  1655. InitializeObjectAttributes(
  1656. &objectAttributes,
  1657. &path,
  1658. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1659. NULL,
  1660. NULL
  1661. );
  1662. status = ZwOpenKey (&parametersHandle, KEY_READ, &objectAttributes);
  1663. if (!NT_SUCCESS(status)) {
  1664. return;
  1665. }
  1666. // Construct value name = "BindingPriority" + transportname
  1667. // First, find the last slash. Then form the value from the prefix and
  1668. // the remainder of the transport name.
  1669. ulength = pTransportName->Length / sizeof(WCHAR);
  1670. for( length = ulength - 1; length != 0; length-- ) {
  1671. if (pTransportName->Buffer[length] == L'\\') {
  1672. break;
  1673. }
  1674. }
  1675. length++;
  1676. key.Buffer = pTransportName->Buffer + length;
  1677. key.Length = (ulength - length) * sizeof(WCHAR);
  1678. value.Buffer = valueBuffer;
  1679. value.MaximumLength = 128 * sizeof(WCHAR);
  1680. value.Length = 0;
  1681. RtlAppendUnicodeToString( &value, L"BindingPriority" );
  1682. RtlAppendUnicodeStringToString( &value, &key );
  1683. // Check if the value is present. If so, replace priority
  1684. // A value of zero is valid and indicates do not bind this one
  1685. status = MRxSmbGetUlongRegistryParameter(
  1686. parametersHandle,
  1687. value.Buffer,
  1688. (PULONG)&temp,
  1689. FALSE );
  1690. if (NT_SUCCESS(status)) {
  1691. *pPriority = temp;
  1692. }
  1693. ZwClose(parametersHandle);
  1694. }
  1695. VOID
  1696. MRxSmbPnPBindingHandler(
  1697. IN TDI_PNP_OPCODE PnPOpcode,
  1698. IN PUNICODE_STRING pTransportName,
  1699. IN PWSTR BindingList)
  1700. /*++
  1701. Routine Description:
  1702. The TDI callbacks routine for binding changes
  1703. Arguments:
  1704. PnPOpcode - the PNP op code
  1705. pTransportName - the transport name
  1706. BindingList - the binding order
  1707. --*/
  1708. {
  1709. ULONG Priority;
  1710. PAGED_CODE();
  1711. switch (PnPOpcode) {
  1712. case TDI_PNP_OP_ADD:
  1713. {
  1714. BOOLEAN fBindToTransport = FALSE;
  1715. PWSTR pSmbMRxTransports;
  1716. UNICODE_STRING SmbMRxTransport;
  1717. NTSTATUS Status;
  1718. Status = SmbCeGetConfigurationInformation();
  1719. if (Status != STATUS_SUCCESS) {
  1720. return;
  1721. }
  1722. pSmbMRxTransports = (PWSTR)SmbCeContext.Transports.Buffer;
  1723. Priority = 1;
  1724. while (*pSmbMRxTransports) {
  1725. SmbMRxTransport.Length = wcslen(pSmbMRxTransports) * sizeof(WCHAR);
  1726. if (SmbMRxTransport.Length == pTransportName->Length) {
  1727. SmbMRxTransport.MaximumLength = SmbMRxTransport.Length;
  1728. SmbMRxTransport.Buffer = pSmbMRxTransports;
  1729. if (RtlCompareUnicodeString(
  1730. &SmbMRxTransport,
  1731. pTransportName,
  1732. TRUE) == 0) {
  1733. fBindToTransport = TRUE;
  1734. break;
  1735. }
  1736. }
  1737. pSmbMRxTransports += (SmbMRxTransport.Length / sizeof(WCHAR) + 1);
  1738. Priority++;
  1739. }
  1740. // Provide a local registry means to alter binding priority
  1741. if (fBindToTransport) {
  1742. MRxSmbpOverrideBindingPriority( pTransportName, &Priority );
  1743. fBindToTransport = (Priority != 0);
  1744. }
  1745. if (fBindToTransport) {
  1746. InterlockedIncrement(&TdiBindRequestsActive);
  1747. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1748. TRANSPORT_BIND_CONTEXT TransportContext;
  1749. TransportContext.Priority = Priority;
  1750. TransportContext.TransportName = *pTransportName;
  1751. MRxSmbpBindTransportCallback(&TransportContext);
  1752. } else {
  1753. PTRANSPORT_BIND_CONTEXT pNewTransportContext;
  1754. NTSTATUS Status;
  1755. pNewTransportContext = RxAllocatePoolWithTag(
  1756. PagedPool,
  1757. sizeof(TRANSPORT_BIND_CONTEXT) + pTransportName->Length,
  1758. MRXSMB_TRANSPORT_POOLTAG);
  1759. if (pNewTransportContext != NULL) {
  1760. pNewTransportContext->Priority = Priority;
  1761. pNewTransportContext->TransportName.MaximumLength = pTransportName->MaximumLength;
  1762. pNewTransportContext->TransportName.Length = pTransportName->Length;
  1763. pNewTransportContext->TransportName.Buffer = (PWCHAR)((PBYTE)pNewTransportContext +
  1764. sizeof(TRANSPORT_BIND_CONTEXT));
  1765. RtlCopyMemory(
  1766. pNewTransportContext->TransportName.Buffer,
  1767. pTransportName->Buffer,
  1768. pTransportName->Length);
  1769. Status = RxDispatchToWorkerThread(
  1770. MRxSmbDeviceObject,
  1771. CriticalWorkQueue,
  1772. MRxSmbpBindTransportWorkerThreadRoutine,
  1773. pNewTransportContext);
  1774. } else {
  1775. Status = STATUS_INSUFFICIENT_RESOURCES;
  1776. }
  1777. if (Status != STATUS_SUCCESS) {
  1778. InterlockedDecrement(&TdiBindRequestsActive);
  1779. SmbCeSignalNetReadyEvent();
  1780. }
  1781. }
  1782. }
  1783. }
  1784. break;
  1785. case TDI_PNP_OP_DEL:
  1786. {
  1787. PSMBCE_TRANSPORT pTransport;
  1788. pTransport = SmbCeFindTransport(pTransportName);
  1789. if (pTransport != NULL) {
  1790. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1791. MRxSmbpUnbindTransportCallback(pTransport);
  1792. } else {
  1793. NTSTATUS Status;
  1794. Status = RxDispatchToWorkerThread(
  1795. MRxSmbDeviceObject,
  1796. CriticalWorkQueue,
  1797. MRxSmbpUnbindTransportCallback,
  1798. pTransport);
  1799. }
  1800. }
  1801. }
  1802. break;
  1803. case TDI_PNP_OP_UPDATE:
  1804. {
  1805. }
  1806. break;
  1807. case TDI_PNP_OP_NETREADY:
  1808. {
  1809. TdiPnpNetReadyEventReceived = TRUE;
  1810. SmbCeSignalNetReadyEvent();
  1811. }
  1812. break;
  1813. default:
  1814. break;
  1815. }
  1816. if( PnPOpcode != TDI_PNP_OP_NETREADY )
  1817. {
  1818. SmbMRxNotifyChangesToNetBt( PnPOpcode, pTransportName, BindingList );
  1819. }
  1820. }
  1821. NTSTATUS
  1822. MRxSmbPnPPowerHandler(
  1823. IN PUNICODE_STRING DeviceName,
  1824. IN PNET_PNP_EVENT PowerEvent,
  1825. IN PTDI_PNP_CONTEXT Context1,
  1826. IN PTDI_PNP_CONTEXT Context2
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine deals with power changes
  1831. Notes:
  1832. The implementation needs to be completed
  1833. --*/
  1834. {
  1835. NTSTATUS Status;
  1836. LONG NumberOfActiveOpens;
  1837. Status = STATUS_SUCCESS;
  1838. FsRtlEnterFileSystem();
  1839. RxPurgeAllFobxs(MRxSmbDeviceObject);
  1840. RxScavengeAllFobxs(MRxSmbDeviceObject);
  1841. NumberOfActiveOpens = MRxSmbNumberOfSrvOpens;
  1842. switch (PowerEvent->NetEvent) {
  1843. case NetEventQueryPower:
  1844. {
  1845. // If the redirector were to return an error on this request there
  1846. // is no underlying support to tell the user about the files that
  1847. // are open. There are two approaches to doing this.. either the RDR
  1848. // rolls its own UI or the PNP manager provides the infra structure.
  1849. // The problem with the former is that hibernation becomes a painstaking
  1850. // process wherein the user has to contend with a variety of UI.
  1851. // Till this is resolved the decision was to use the power mgmt. API
  1852. // to manage system initiated hibernate requests and succeed user
  1853. // initiated requests after appropriate purging/scavenging.
  1854. Status = STATUS_SUCCESS;
  1855. }
  1856. break;
  1857. case NetEventQueryRemoveDevice:
  1858. {
  1859. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1860. ULONG NumberOfFilesOpen = 0;
  1861. PSMBCE_TRANSPORT pTransport = NULL;
  1862. pTransport = SmbCeFindTransport(DeviceName);
  1863. if (pTransport != NULL) {
  1864. SmbCeAcquireSpinLock();
  1865. pServerEntry = SmbCeGetFirstServerEntry();
  1866. while (pServerEntry != NULL) {
  1867. if ((pServerEntry->pTransport != NULL) &&
  1868. (pTransport == pServerEntry->pTransport->pTransport)) {
  1869. NumberOfFilesOpen += pServerEntry->Server.NumberOfSrvOpens;
  1870. }
  1871. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1872. }
  1873. SmbCeReleaseSpinLock();
  1874. SmbCeDereferenceTransport(pTransport);
  1875. }
  1876. }
  1877. break;
  1878. default:
  1879. break;
  1880. }
  1881. FsRtlExitFileSystem();
  1882. return Status;
  1883. }
  1884. NTSTATUS
  1885. MRxSmbRegisterForPnpNotifications()
  1886. /*++
  1887. Routine Description:
  1888. This routine registers with TDI for receiving transport notifications
  1889. --*/
  1890. {
  1891. NTSTATUS Status = STATUS_SUCCESS;
  1892. PAGED_CODE();
  1893. if(MRxSmbTdiNotificationHandle == NULL ) {
  1894. UNICODE_STRING ClientName;
  1895. TDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo;
  1896. RtlInitUnicodeString(&ClientName,L"LanmanWorkStation");
  1897. ClientInterfaceInfo.MajorTdiVersion = 2;
  1898. ClientInterfaceInfo.MinorTdiVersion = 0;
  1899. ClientInterfaceInfo.Unused = 0;
  1900. ClientInterfaceInfo.ClientName = &ClientName;
  1901. ClientInterfaceInfo.BindingHandler = MRxSmbPnPBindingHandler;
  1902. ClientInterfaceInfo.AddAddressHandler = NULL;
  1903. ClientInterfaceInfo.DelAddressHandler = NULL;
  1904. ClientInterfaceInfo.PnPPowerHandler = MRxSmbPnPPowerHandler;
  1905. KeInitializeEvent(
  1906. &TdiNetStartupCompletionEvent,
  1907. NotificationEvent,
  1908. FALSE);
  1909. Status = TdiRegisterPnPHandlers (
  1910. &ClientInterfaceInfo,
  1911. sizeof(ClientInterfaceInfo),
  1912. &MRxSmbTdiNotificationHandle );
  1913. if (Status == STATUS_SUCCESS) {
  1914. LARGE_INTEGER WaitInterval;
  1915. WaitInterval.QuadPart = -( 10000 * 2 * 60 * 1000 );
  1916. Status = KeWaitForSingleObject(
  1917. &TdiNetStartupCompletionEvent,
  1918. Executive,
  1919. KernelMode,
  1920. FALSE,
  1921. &WaitInterval);
  1922. if (Status != STATUS_SUCCESS) {
  1923. DbgPrint("MRxSmb Finishes waiting on TDI_PNP_OP_NETREADY %lx\n",Status);
  1924. }
  1925. }
  1926. }
  1927. return Status;
  1928. }
  1929. NTSTATUS
  1930. MRxSmbDeregisterForPnpNotifications()
  1931. /*++
  1932. Routine Description:
  1933. This routine deregisters the TDI notification mechanism
  1934. Notes:
  1935. --*/
  1936. {
  1937. NTSTATUS Status = STATUS_SUCCESS;
  1938. PAGED_CODE();
  1939. if( MRxSmbTdiNotificationHandle != NULL ) {
  1940. Status = TdiDeregisterPnPHandlers( MRxSmbTdiNotificationHandle );
  1941. if( NT_SUCCESS( Status ) ) {
  1942. MRxSmbTdiNotificationHandle = NULL;
  1943. }
  1944. }
  1945. return Status;
  1946. }
  1947. #endif
  1948. NTSTATUS
  1949. SmbCePnpBindBrowser( PUNICODE_STRING pTransportName, BOOLEAN IsBind)
  1950. /*++
  1951. Routine Description:
  1952. This routine binds the browser with the specified transport
  1953. Arguments:
  1954. pTransportName - the name of the transport
  1955. Notes:
  1956. --*/
  1957. {
  1958. NTSTATUS Status;
  1959. HANDLE BrowserHandle;
  1960. PLMDR_REQUEST_PACKET pLmdrRequestPacket;
  1961. IO_STATUS_BLOCK IoStatusBlock;
  1962. OBJECT_ATTRIBUTES ObjectAttributes;
  1963. UNICODE_STRING BrowserDeviceName;
  1964. ULONG LmdrRequestPacketSize;
  1965. PAGED_CODE();
  1966. //
  1967. // Open up a handle to the browser
  1968. //
  1969. RtlInitUnicodeString( &BrowserDeviceName, DD_BROWSER_DEVICE_NAME_U);
  1970. InitializeObjectAttributes(
  1971. &ObjectAttributes,
  1972. &BrowserDeviceName,
  1973. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1974. NULL,
  1975. NULL
  1976. );
  1977. Status = IoCreateFile(
  1978. &BrowserHandle, // FileHandle
  1979. SYNCHRONIZE, // DesiredAccess
  1980. &ObjectAttributes, // ObjectAttributes
  1981. &IoStatusBlock, // IoStatusBlock
  1982. NULL, // AllocationSize
  1983. 0L, // FileAttributes
  1984. FILE_SHARE_VALID_FLAGS, // ShareAccess
  1985. FILE_OPEN, // Disposition
  1986. FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions
  1987. NULL, // EaBuffer
  1988. 0, // EaLength
  1989. CreateFileTypeNone, // CreateFileType
  1990. NULL, // ExtraCreateParameters
  1991. 0 // Options
  1992. );
  1993. if( NT_SUCCESS( Status ) ) {
  1994. Status = IoStatusBlock.Status;
  1995. }
  1996. if( !NT_SUCCESS(Status ) ) {
  1997. return Status;
  1998. }
  1999. // The browser requires that the computer name and the domain name be
  2000. // concatenated to the transport name and passed on. Since no length
  2001. // fields are provided to supply the length of these two names the
  2002. // NULL delimiter needs to be attached. This accounts for the two
  2003. // additional characters in the calculation
  2004. LmdrRequestPacketSize = sizeof(*pLmdrRequestPacket) +
  2005. pTransportName->Length +
  2006. SmbCeContext.DomainName.Length + sizeof(WCHAR) +
  2007. SmbCeContext.ComputerName.Length + sizeof(WCHAR);
  2008. pLmdrRequestPacket = RxAllocatePoolWithTag(
  2009. NonPagedPool,
  2010. LmdrRequestPacketSize,
  2011. MRXSMB_TRANSPORT_POOLTAG);
  2012. if (pLmdrRequestPacket != NULL) {
  2013. ULONG BufferOffset = 0;
  2014. PVOID pBuffer;
  2015. WCHAR NullChar = L'\0';
  2016. ULONG BindMode;
  2017. //
  2018. // Tell the browser to bind to this new transport
  2019. //
  2020. RtlZeroMemory( pLmdrRequestPacket, sizeof(LMDR_REQUEST_PACKET));
  2021. pLmdrRequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  2022. pLmdrRequestPacket->Parameters.Bind.TransportNameLength = pTransportName->Length;
  2023. pBuffer = pLmdrRequestPacket->Parameters.Bind.TransportName;
  2024. RtlCopyMemory(
  2025. pBuffer,
  2026. pTransportName->Buffer,
  2027. pTransportName->Length);
  2028. BufferOffset = pTransportName->Length;
  2029. // Tell the browser our computer name.
  2030. pLmdrRequestPacket->Level = TRUE; // Emulated computer name follows transport name.
  2031. RtlCopyMemory(
  2032. ((PBYTE)pBuffer + BufferOffset),
  2033. SmbCeContext.ComputerName.Buffer,
  2034. SmbCeContext.ComputerName.Length);
  2035. BufferOffset += SmbCeContext.ComputerName.Length;
  2036. RtlCopyMemory(
  2037. ((PBYTE)pBuffer + BufferOffset),
  2038. &NullChar,
  2039. sizeof(WCHAR));
  2040. BufferOffset += sizeof(WCHAR);
  2041. // Tell the browser our domain name.
  2042. pLmdrRequestPacket->EmulatedDomainName.Buffer = (LPWSTR)
  2043. ((PBYTE)pBuffer + BufferOffset);
  2044. pLmdrRequestPacket->EmulatedDomainName.MaximumLength =
  2045. pLmdrRequestPacket->EmulatedDomainName.Length =
  2046. SmbCeContext.DomainName.Length;
  2047. RtlCopyMemory(
  2048. ((PBYTE)pBuffer + BufferOffset),
  2049. SmbCeContext.DomainName.Buffer,
  2050. SmbCeContext.DomainName.Length);
  2051. BufferOffset += SmbCeContext.DomainName.Length;
  2052. RtlCopyMemory(
  2053. ((PBYTE)pBuffer + BufferOffset),
  2054. &NullChar,
  2055. sizeof(WCHAR));
  2056. BufferOffset += sizeof(WCHAR);
  2057. BindMode = IsBind?
  2058. IOCTL_LMDR_BIND_TO_TRANSPORT_DOM:
  2059. IOCTL_LMDR_UNBIND_FROM_TRANSPORT_DOM;
  2060. Status = NtDeviceIoControlFile(
  2061. BrowserHandle, // FileHandle
  2062. NULL, // Event
  2063. NULL, // ApcRoutine
  2064. NULL, // ApcContext
  2065. &IoStatusBlock, // IoStatusBlock
  2066. BindMode, // IoControlCode
  2067. pLmdrRequestPacket, // InputBuffer
  2068. LmdrRequestPacketSize, // InputBufferLength
  2069. NULL, // OutputBuffer
  2070. 0 // OutputBufferLength
  2071. );
  2072. RxFreePool(pLmdrRequestPacket);
  2073. if( NT_SUCCESS(Status ) ) {
  2074. Status = IoStatusBlock.Status;
  2075. }
  2076. }
  2077. ZwClose( BrowserHandle );
  2078. return Status;
  2079. }
  2080. PSMBCE_TRANSPORT_ARRAY
  2081. SmbCeReferenceTransportArray(VOID)
  2082. /*++
  2083. Routine Description:
  2084. This routine references and returns the current transport array instance
  2085. Return Value:
  2086. PSMBCE_TRANSPORT_ARRAY - the pointer of the current transport array instance
  2087. Notes:
  2088. --*/
  2089. {
  2090. KIRQL SavedIrql;
  2091. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  2092. KeAcquireSpinLock(&MRxSmbTransports.Lock,&SavedIrql);
  2093. pTransportArray = MRxSmbTransports.pTransportArray;
  2094. if (pTransportArray != NULL) {
  2095. InterlockedIncrement(&pTransportArray->ReferenceCount);
  2096. }
  2097. KeReleaseSpinLock(&MRxSmbTransports.Lock,SavedIrql);
  2098. return pTransportArray;
  2099. }
  2100. NTSTATUS
  2101. SmbCeDereferenceTransportArray(
  2102. PSMBCE_TRANSPORT_ARRAY pTransportArray)
  2103. /*++
  2104. Routine Description:
  2105. This routine dereferences the transport array instance
  2106. Arguments:
  2107. pTransportArray - the transport array instance
  2108. Return Value:
  2109. STATUS_SUCCESS - the server transport was successfully dereferenced
  2110. Other Status codes correspond to error situations.
  2111. Notes:
  2112. --*/
  2113. {
  2114. KIRQL SavedIrql;
  2115. NTSTATUS Status = STATUS_SUCCESS;
  2116. PAGED_CODE();
  2117. if (pTransportArray != NULL) {
  2118. ASSERT( pTransportArray->ReferenceCount > 0 );
  2119. if(InterlockedDecrement(&pTransportArray->ReferenceCount)==0) {
  2120. ULONG i;
  2121. for(i=0;i<pTransportArray->Count;i++) {
  2122. SmbCeDereferenceTransport(pTransportArray->SmbCeTransports[i]);
  2123. }
  2124. RxFreePool(pTransportArray->SmbCeTransports);
  2125. RxFreePool(pTransportArray->LocalAddresses);
  2126. RxFreePool(pTransportArray);
  2127. }
  2128. } else {
  2129. Status = STATUS_INVALID_PARAMETER;
  2130. }
  2131. return Status;
  2132. }
  2133. NTSTATUS
  2134. SmbCeIsServerAvailable(
  2135. PUNICODE_STRING Name
  2136. )
  2137. /*++
  2138. Routine Description:
  2139. This routine scans the list of "unreachable" servers and returns the status
  2140. of the last failed connection attempt.
  2141. Return:
  2142. STATUS_SUCCESS -> we have no reason to believe this server is unreachable
  2143. other -> server is unreachable for this reason
  2144. --*/
  2145. {
  2146. PUNAVAILABLE_SERVER server;
  2147. LARGE_INTEGER now;
  2148. NTSTATUS status = STATUS_SUCCESS;
  2149. PAGED_CODE();
  2150. KeQueryTickCount( &now );
  2151. ExAcquireResourceExclusive( &UnavailableServerListResource, TRUE );
  2152. for( server = (PUNAVAILABLE_SERVER)UnavailableServerList.Flink;
  2153. server != (PUNAVAILABLE_SERVER)&UnavailableServerList;
  2154. server = (PUNAVAILABLE_SERVER)server->ListEntry.Flink ) {
  2155. //
  2156. // If this entry has timed out, remove it.
  2157. //
  2158. if( now.QuadPart > server->Time.QuadPart ) {
  2159. PUNAVAILABLE_SERVER tmp;
  2160. //
  2161. // Unlink this entry from the list and discard it
  2162. //
  2163. tmp = (PUNAVAILABLE_SERVER)(server->ListEntry.Blink);
  2164. RemoveEntryList( &server->ListEntry );
  2165. RxFreePool( server );
  2166. server = tmp;
  2167. continue;
  2168. }
  2169. //
  2170. // See if this entry is the one we want
  2171. //
  2172. if( RtlCompareUnicodeString( &server->Name, Name, TRUE ) == 0 ) {
  2173. status = server->Status;
  2174. RxDbgTrace(0, Dbg, ("SmbCeIsServerAvailable: Found %wZ %X\n",
  2175. &server->Name, status ));
  2176. }
  2177. }
  2178. ExReleaseResource( &UnavailableServerListResource );
  2179. return status;
  2180. }
  2181. VOID
  2182. SmbCeServerIsUnavailable(
  2183. PUNICODE_STRING Name,
  2184. NTSTATUS Status
  2185. )
  2186. {
  2187. PUNAVAILABLE_SERVER server;
  2188. LARGE_INTEGER CurrentTime;
  2189. LARGE_INTEGER ExpiryTimeInTicks;
  2190. PAGED_CODE();
  2191. server = (PUNAVAILABLE_SERVER)RxAllocatePoolWithTag(
  2192. PagedPool,
  2193. sizeof( *server ) + Name->Length,
  2194. MRXSMB_TRANSPORT_POOLTAG
  2195. );
  2196. if( server == NULL ) {
  2197. return;
  2198. }
  2199. RxDbgTrace(0, Dbg, ("SmbCeServerIsUnavailable: Add %wZ %X\n", Name, Status ));
  2200. server->Name.Buffer = (PUSHORT)(server + 1);
  2201. server->Name.MaximumLength = Name->Length;
  2202. RtlCopyUnicodeString( &server->Name, Name );
  2203. KeQueryTickCount( &CurrentTime );
  2204. ExpiryTimeInTicks.QuadPart = (1000 * 1000 * 10) / KeQueryTimeIncrement();
  2205. ExpiryTimeInTicks.QuadPart = UNAVAILABLE_SERVER_TIME * ExpiryTimeInTicks.QuadPart;
  2206. server->Time.QuadPart = CurrentTime.QuadPart + ExpiryTimeInTicks.QuadPart;
  2207. server->Status = Status;
  2208. ExAcquireResourceExclusive( &UnavailableServerListResource, TRUE );
  2209. InsertHeadList( &UnavailableServerList, &server->ListEntry );
  2210. ExReleaseResource( &UnavailableServerListResource );
  2211. }
  2212. VOID
  2213. SmbCeDiscardUnavailableServerList(
  2214. )
  2215. {
  2216. PUNAVAILABLE_SERVER server;
  2217. PAGED_CODE();
  2218. RxDbgTrace(0, Dbg, ("SmbCeDiscardUnavailableServerList\n" ));
  2219. ExAcquireResourceExclusive( &UnavailableServerListResource, TRUE );
  2220. while( UnavailableServerList.Flink != &UnavailableServerList ) {
  2221. server = (PUNAVAILABLE_SERVER)UnavailableServerList.Flink;
  2222. RemoveEntryList( &server->ListEntry );
  2223. RxFreePool( server );
  2224. }
  2225. ExReleaseResource( &UnavailableServerListResource );
  2226. }
  2227. extern BOOLEAN SetupInProgress;
  2228. VOID
  2229. MRxSmbLogTransportError(
  2230. PUNICODE_STRING pTransportName,
  2231. PUNICODE_STRING pDomainName,
  2232. NTSTATUS ErrorStatus,
  2233. IN ULONG Id)
  2234. /*++
  2235. Routine Description:
  2236. This routine reports the error that occurs at binding the browser with the specified transport
  2237. Arguments:
  2238. pTransportName - the name of the transport
  2239. Status - the NT status of the error occured
  2240. Notes:
  2241. --*/
  2242. {
  2243. NTSTATUS Status;
  2244. USHORT RemainingLength = ERROR_LOG_MAXIMUM_SIZE - sizeof(IO_ERROR_LOG_PACKET) - 3*sizeof(UNICODE_NULL);
  2245. UNICODE_STRING ErrorLog[3];
  2246. UNICODE_STRING UnicodeStatus;
  2247. UNICODE_STRING TempUnicode;
  2248. ULONG DosError;
  2249. // strip of the "\device\" at the beginning of transport name to reduce the message length
  2250. pTransportName->Length -= 8*sizeof(UNICODE_NULL);
  2251. // assume the dos error code won't be larger than 10 digits
  2252. UnicodeStatus.Length = 12 * sizeof(UNICODE_NULL);
  2253. UnicodeStatus.MaximumLength = UnicodeStatus.Length;
  2254. UnicodeStatus.Buffer = RxAllocatePoolWithTag(NonPagedPool,
  2255. UnicodeStatus.Length,
  2256. MRXSMB_TRANSPORT_POOLTAG);
  2257. if (UnicodeStatus.Buffer == NULL) {
  2258. goto FINALY;
  2259. }
  2260. // use the dos error code to display the status on the event message
  2261. UnicodeStatus.Buffer[0] = L'%';
  2262. UnicodeStatus.Buffer[1] = L'%';
  2263. DosError = RtlNtStatusToDosError(ErrorStatus);
  2264. TempUnicode.Length = UnicodeStatus.Length - 2*sizeof(UNICODE_NULL);
  2265. TempUnicode.MaximumLength = UnicodeStatus.MaximumLength - 2*sizeof(UNICODE_NULL);
  2266. TempUnicode.Buffer = &UnicodeStatus.Buffer[2];
  2267. Status = RtlIntegerToUnicodeString(
  2268. DosError,
  2269. 0,
  2270. &TempUnicode);
  2271. if (Status != STATUS_SUCCESS) {
  2272. goto FINALY;
  2273. }
  2274. ErrorLog[2].Length = TempUnicode.Length + 2*sizeof(UNICODE_NULL);
  2275. ErrorLog[2].MaximumLength = ErrorLog[2].Length;
  2276. ErrorLog[2].Buffer = UnicodeStatus.Buffer;
  2277. RemainingLength -= ErrorLog[2].Length;
  2278. if (pDomainName->Length + pTransportName->Length > RemainingLength) {
  2279. // the length error log message is limited by the ERROR_LOG_MAXIMUM_SIZE. This restriction can be
  2280. // enfored by truncating the doamin and transport names so that both of them can get chance to be
  2281. // displayed on the EvenLog.
  2282. ErrorLog[0].Length = pDomainName->Length < RemainingLength / 2 ?
  2283. pDomainName->Length :
  2284. RemainingLength / 2;
  2285. RemainingLength -= ErrorLog[0].Length;
  2286. ErrorLog[1].Length = pTransportName->Length < RemainingLength ?
  2287. pTransportName->Length :
  2288. RemainingLength;
  2289. } else {
  2290. ErrorLog[0].Length = pDomainName->Length;
  2291. ErrorLog[1].Length = pTransportName->Length;
  2292. }
  2293. ErrorLog[0].MaximumLength = ErrorLog[0].Length;
  2294. ErrorLog[1].MaximumLength = ErrorLog[1].Length;
  2295. ErrorLog[0].Buffer = pDomainName->Buffer;
  2296. // strip of the "\device\" at the beginning of transport name
  2297. ErrorLog[1].Buffer = &pTransportName->Buffer[8];
  2298. RxLogEventWithAnnotation (
  2299. MRxSmbDeviceObject,
  2300. Id,
  2301. ErrorStatus,
  2302. NULL,
  2303. 0,
  2304. ErrorLog,
  2305. 3
  2306. );
  2307. FINALY:
  2308. // restore the length with "\device\" at the beginning of transport name
  2309. pTransportName->Length += 8*sizeof(UNICODE_NULL);
  2310. if (UnicodeStatus.Buffer != NULL) {
  2311. RxFreePool(UnicodeStatus.Buffer);
  2312. }
  2313. if (!SetupInProgress && ErrorStatus == STATUS_DUPLICATE_NAME) {
  2314. IoRaiseInformationalHardError(ErrorStatus, NULL, NULL);
  2315. }
  2316. }
  2317. VOID
  2318. SmbMRxNotifyChangesToNetBt(
  2319. IN TDI_PNP_OPCODE PnPOpcode,
  2320. IN PUNICODE_STRING DeviceName,
  2321. IN PWSTR MultiSZBindList)
  2322. /*++
  2323. Routine Description:
  2324. This routine should not be part of rdr. It has been introduced into this
  2325. component to overcome current limitations in NetBt. The NetBt transport
  2326. exposes two kinds of devices -- the traditional NetBt device and the
  2327. new non Netbios device which make use of the NetBt framing code without the
  2328. name resolution aspects of it. The current implementation in NetBt exposes
  2329. the former devices on a per adapter basis while the second category of device
  2330. is exposed on a global basis ( one for all the adapters ). This poses
  2331. problems in disabling/enabling srv on a given adapter.
  2332. The correct solution is to expose the second category of devices on a per
  2333. adapter basis. Till it is done this workaround is reqd. With this workaround
  2334. whenever the server is notified of any changes to the binding string it turns
  2335. around and notifies the NetBt transport about these changes.
  2336. This routine is based upon the following assumptions ...
  2337. 1) The notification from TDI is not done at raised IRQL.
  2338. 2) The thread on which this notification occurs has enough access rights.
  2339. 3) The notification to NetBt is done asynchronously with srv's reaction
  2340. to the change. The srv handles the PNP notification by passing it off to
  2341. user mode and have it come through the server service.
  2342. Arguments:
  2343. PNPOpcode - the PNP opcode
  2344. DeviceName - the transport for which this opcode is intended
  2345. MultiSZBindList - the binding list
  2346. Return Value:
  2347. None.
  2348. --*/
  2349. {
  2350. NTSTATUS Status;
  2351. OBJECT_ATTRIBUTES ObjectAttributes;
  2352. HANDLE NetbioslessSmbHandle;
  2353. IO_STATUS_BLOCK IoStatusBlock;
  2354. UNICODE_STRING NetbioslessSmbName = {36,36, L"\\device\\NetbiosSmb"};
  2355. InitializeObjectAttributes(
  2356. &ObjectAttributes,
  2357. &NetbioslessSmbName,
  2358. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2359. NULL,
  2360. NULL );
  2361. Status = ZwCreateFile (
  2362. &NetbioslessSmbHandle,
  2363. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access
  2364. &ObjectAttributes, // object attributes
  2365. &IoStatusBlock, // returned status information
  2366. NULL, // block size (unused)
  2367. 0, // file attributes
  2368. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  2369. FILE_CREATE, // create disposition
  2370. 0, // create options
  2371. NULL, // EA buffer
  2372. 0 // EA length
  2373. );
  2374. if ( NT_SUCCESS(Status) ) {
  2375. NETBT_SMB_BIND_REQUEST NetBtNotificationParameters;
  2376. NetBtNotificationParameters.RequestType = SMB_CLIENT;
  2377. NetBtNotificationParameters.PnPOpCode = PnPOpcode;
  2378. NetBtNotificationParameters.pDeviceName = DeviceName;
  2379. NetBtNotificationParameters.MultiSZBindList = MultiSZBindList;
  2380. Status = ZwDeviceIoControlFile(
  2381. NetbioslessSmbHandle,
  2382. NULL,
  2383. NULL,
  2384. NULL,
  2385. &IoStatusBlock,
  2386. IOCTL_NETBT_SET_SMBDEVICE_BIND_INFO,
  2387. &NetBtNotificationParameters,
  2388. sizeof(NetBtNotificationParameters),
  2389. NULL,
  2390. 0);
  2391. Status = ZwClose(NetbioslessSmbHandle);
  2392. }
  2393. }
  2394.