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.

2487 lines
77 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. vcsndrcv.c
  5. Abstract:
  6. This module implements all functions related to transmitting and recieving SMB's on a
  7. connection based transport.
  8. Revision History:
  9. Balan Sethu Raman [SethuR] 6-March-1995
  10. Notes:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "vcsndrcv.h"
  15. #include "nbtioctl.h"
  16. //
  17. // Forward declarations
  18. //
  19. NTSTATUS
  20. VctTranceive(
  21. PSMBCE_SERVER_TRANSPORT pTransport,
  22. PSMBCEDB_SERVER_ENTRY pServerEntry,
  23. PSMB_EXCHANGE pExchange,
  24. ULONG SendOptions,
  25. PMDL pSmbMdl,
  26. ULONG SendLength,
  27. PVOID pSendCompletionContext);
  28. NTSTATUS
  29. VctReceive(
  30. PSMBCE_SERVER_TRANSPORT pTransport,
  31. PSMBCEDB_SERVER_ENTRY pServerEntry,
  32. PSMB_EXCHANGE pExchange);
  33. NTSTATUS
  34. VctSend(
  35. PSMBCE_SERVER_TRANSPORT pTransport,
  36. PSMBCEDB_SERVER_ENTRY pServerEntry,
  37. ULONG SendOptions,
  38. PMDL pSmbMdl,
  39. ULONG SendLength,
  40. PVOID pSendCompletionContext);
  41. NTSTATUS
  42. VctSendDatagram(
  43. PSMBCE_SERVER_TRANSPORT pTransport,
  44. PSMBCEDB_SERVER_ENTRY pServerEntry,
  45. ULONG SendOptions,
  46. PMDL pSmbMdl,
  47. ULONG SendLength,
  48. PVOID pSendCompletionContext);
  49. struct _SMBCE_VC *
  50. VctSelectVc(
  51. struct SMBCE_SERVER_VC_TRANSPORT *pVcTransport,
  52. BOOLEAN fMultiplexed);
  53. NTSTATUS
  54. VctInitializeExchange(
  55. PSMBCE_SERVER_TRANSPORT pTransport,
  56. PSMB_EXCHANGE pExchange);
  57. NTSTATUS
  58. VctUninitializeExchange(
  59. PSMBCE_SERVER_TRANSPORT pTransport,
  60. PSMB_EXCHANGE pExchange);
  61. NTSTATUS
  62. VctIndReceive(
  63. IN PVOID pEventContext,
  64. IN PRXCE_VC pVc,
  65. IN ULONG ReceiveFlags,
  66. IN ULONG BytesIndicated,
  67. IN ULONG BytesAvailable,
  68. OUT ULONG *pBytesTaken,
  69. IN PVOID pTsdu,
  70. OUT PMDL *pDataBufferPointer,
  71. OUT PULONG pDataBufferSize
  72. );
  73. NTSTATUS
  74. VctIndDataReady(
  75. IN PVOID pEventContext,
  76. IN PMDL pBuffer,
  77. IN ULONG DataSize,
  78. IN NTSTATUS CopyDataStatus
  79. );
  80. NTSTATUS
  81. VctIndEndpointError(
  82. IN PVOID pEventContext,
  83. IN NTSTATUS IndicatedStatus
  84. );
  85. NTSTATUS
  86. VctIndSendPossible(
  87. IN PVOID pEventContext,
  88. IN PRXCE_VC pRxCeVc,
  89. IN ULONG BytesAvailable
  90. );
  91. NTSTATUS
  92. VctIndReceiveDatagram(
  93. IN PVOID pRxCeEventContext,
  94. IN int SourceAddressLength,
  95. IN PVOID SourceAddress,
  96. IN int OptionsLength,
  97. IN PVOID Options,
  98. IN ULONG ReceiveDatagramFlags,
  99. IN ULONG BytesIndicated,
  100. IN ULONG BytesAvailable,
  101. OUT ULONG *BytesTaken,
  102. IN PVOID Tsdu,
  103. OUT PMDL *pDataBufferPointer,
  104. OUT PULONG pDataBufferSize
  105. );
  106. NTSTATUS
  107. VctIndSendComplete(
  108. IN PVOID pEventContext,
  109. IN PRXCE_VC pRxCeVc,
  110. IN PVOID pCompletionContext,
  111. IN NTSTATUS SendCompletionStatus
  112. );
  113. NTSTATUS
  114. VctCompleteInitialization(
  115. PSMBCEDB_SERVER_ENTRY pServerEntry,
  116. PSMBCE_TRANSPORT pTransport,
  117. struct SMBCE_SERVER_VC_TRANSPORT *pVcTransport);
  118. NTSTATUS
  119. VctUninitialize(
  120. PVOID pTransport);
  121. NTSTATUS
  122. VctpTranslateNetbiosNameToIpAddress(
  123. IN OEM_STRING *pName,
  124. OUT ULONG *pIpAddress
  125. );
  126. ULONG
  127. VctComputeTransportAddressSize(
  128. IN PUNICODE_STRING pServerName);
  129. NTSTATUS
  130. VctBuildTransportAddress (
  131. IN PTRANSPORT_ADDRESS pTransportAddress,
  132. IN ULONG TransportAddressLength,
  133. IN PUNICODE_STRING pServerName,
  134. OUT PULONG pServerIpAddress
  135. );
  136. NTSTATUS
  137. VctpCreateConnection(
  138. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  139. IN PTRANSPORT_ADDRESS pTransportAddress,
  140. IN ULONG TransportAddressLength,
  141. IN PUNICODE_STRING pServerName,
  142. OUT PSMBCE_TRANSPORT *pTransportPtr,
  143. IN OUT PRXCE_CONNECTION pRxCeConnection,
  144. IN OUT PRXCE_VC pRxCeVc);
  145. VOID
  146. VctpInitializeServerTransport(
  147. struct _RXCE_VC_CONNECT_CONTEXT *pRxCeConnectContext);
  148. NTSTATUS
  149. VctpInvokeTransportFunction(
  150. struct _RXCE_VC_CONNECT_CONTEXT *pRxCeConnectContext);
  151. VOID
  152. VctpUninitializeServerTransport(
  153. struct _RXCE_VC_CONNECT_CONTEXT *pRxCeConnectContext);
  154. NTSTATUS
  155. VctTearDownServerTransport(
  156. PSMBCE_SERVER_TRANSPORT pServerTransport);
  157. NTSTATUS
  158. VctInitiateDisconnect(
  159. PSMBCE_SERVER_TRANSPORT pServerTransport);
  160. #ifdef ALLOC_PRAGMA
  161. #pragma alloc_text(PAGE, VctTranceive)
  162. #pragma alloc_text(PAGE, VctReceive)
  163. #pragma alloc_text(PAGE, VctSend)
  164. #pragma alloc_text(PAGE, VctSendDatagram)
  165. #pragma alloc_text(PAGE, VctSelectVc)
  166. #pragma alloc_text(PAGE, VctInitializeExchange)
  167. #pragma alloc_text(PAGE, VctUninitializeExchange)
  168. #pragma alloc_text(PAGE, VctIndEndpointError)
  169. #pragma alloc_text(PAGE, VctIndSendPossible)
  170. #pragma alloc_text(PAGE, VctCompleteInitialization)
  171. #pragma alloc_text(PAGE, VctUninitialize)
  172. #pragma alloc_text(PAGE, VctpTranslateNetbiosNameToIpAddress)
  173. #pragma alloc_text(PAGE, VctComputeTransportAddressSize)
  174. #pragma alloc_text(PAGE, VctBuildTransportAddress)
  175. #pragma alloc_text(PAGE, VctpCreateConnection)
  176. #pragma alloc_text(PAGE, VctpInitializeServerTransport)
  177. #pragma alloc_text(PAGE, VctpUninitializeServerTransport)
  178. #pragma alloc_text(PAGE, VctpInvokeTransportFunction)
  179. #pragma alloc_text(PAGE, VctInstantiateServerTransport)
  180. #pragma alloc_text(PAGE, VctTearDownServerTransport)
  181. #pragma alloc_text(PAGE, VctInitiateDisconnect)
  182. #endif
  183. RXDT_DefineCategory(VCSNDRCV);
  184. #define Dbg (DEBUG_TRACE_VCSNDRCV)
  185. // Move this def to a common .h file.
  186. #define MAX_SMB_PACKET_SIZE (65536)
  187. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  188. //
  189. // Forward references of functions ....
  190. //
  191. extern NTSTATUS
  192. VctTearDownServerTransport(
  193. PSMBCE_SERVER_TRANSPORT pTransport);
  194. extern NTSTATUS
  195. VctInitializeExchange(
  196. PSMBCE_SERVER_TRANSPORT pTransport,
  197. PSMB_EXCHANGE pExchange);
  198. extern PSMBCE_VC
  199. VctSelectVc(
  200. PSMBCE_SERVER_VC_TRANSPORT pVcTransport,
  201. BOOLEAN fMultiplexed);
  202. extern NTSTATUS
  203. SmbCeReceiveIndWithSecuritySignature(
  204. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  205. IN ULONG BytesIndicated,
  206. IN ULONG BytesAvailable,
  207. OUT ULONG *pBytesTaken,
  208. IN PVOID pTsdu,
  209. OUT PMDL *pDataBufferPointer,
  210. OUT PULONG pDataBufferSize,
  211. IN ULONG ReceiveFlags
  212. );
  213. extern NTSTATUS
  214. SmbCeDataReadyIndWithSecuritySignature(
  215. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  216. IN PMDL pBuffer,
  217. IN ULONG DataSize,
  218. IN NTSTATUS CopyDataStatus);
  219. #define SmbMmInitializeVcEntry(pVcEntry) \
  220. SmbMmInitializeHeader((pVcEntry));
  221. #define SmbMmUninitializeVcEntry(pVcEntry) \
  222. ASSERT(IsListEmpty(&(pVcEntry)->Requests.ListHead))
  223. #define VctSelectMultiplexedVcEntry(pVcTransport) VctSelectVc(pVcTransport,TRUE)
  224. #define VctSelectRawVcEntry(pVcTransport) VctSelectVc(pVcTransport,FALSE)
  225. //
  226. // Inline functions to update the state of a VC.
  227. //
  228. INLINE BOOLEAN
  229. VctUpdateVcStateLite(
  230. PSMBCE_VC pVc,
  231. SMBCE_VC_STATE NewState)
  232. {
  233. BOOLEAN Result = TRUE;
  234. ASSERT(SmbCeSpinLockAcquired());
  235. if (NewState == SMBCE_VC_STATE_RAW) {
  236. if (pVc->SwizzleCount != 0) {
  237. Result = FALSE;
  238. } else {
  239. pVc->State = NewState;
  240. }
  241. } else {
  242. pVc->State = NewState;
  243. }
  244. return Result;
  245. }
  246. INLINE BOOLEAN
  247. VctUpdateVcState(
  248. PSMBCE_VC pVc,
  249. SMBCE_VC_STATE NewState)
  250. {
  251. BOOLEAN Result = TRUE;
  252. SmbCeAcquireSpinLock();
  253. Result = VctUpdateVcStateLite(pVc,NewState);
  254. SmbCeReleaseSpinLock();
  255. return Result;
  256. }
  257. NTSTATUS
  258. VctTranceive(
  259. PSMBCE_SERVER_TRANSPORT pTransport,
  260. PSMBCEDB_SERVER_ENTRY pServerEntry,
  261. PSMB_EXCHANGE pExchange,
  262. ULONG SendOptions,
  263. PMDL pSmbMdl,
  264. ULONG SendLength,
  265. PVOID pSendCompletionContext)
  266. /*++
  267. Routine Description:
  268. This routine transmits/receives a SMB for a give exchange
  269. Arguments:
  270. pTransport - the transport
  271. pServerEntry - the server entry
  272. pExchange - the exchange instance issuing this SMB.
  273. SendOptions - options for send
  274. pSmbMdl - the SMB that needs to be sent.
  275. SendLength - length of data to be transmitted
  276. pSendCompletionContext - the send completion context
  277. Return Value:
  278. STATUS_SUCCESS - the server call construction has been finalized.
  279. STATUS_PENDING - the open involves network traffic and the exchange has been
  280. queued for notification ( pServerPointer is set to NULL)
  281. Other Status codes correspond to error situations.
  282. --*/
  283. {
  284. NTSTATUS Status = STATUS_SUCCESS;
  285. PSMBCE_VC pVc;
  286. PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
  287. PSMB_HEADER pSmbHeader = MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  288. USHORT Mid;
  289. BOOLEAN fInvokeSendCompleteHandler = TRUE;
  290. PAGED_CODE();
  291. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  292. if (pSmbHeader == NULL) {
  293. Status = STATUS_INSUFFICIENT_RESOURCES;
  294. } else {
  295. pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  296. // Ensure that the connection is still active before satisfying the request.
  297. if (SmbCeIsEntryInUse(&pServerEntry->Header)) {
  298. pVc = pExchange->SmbCeContext.TransportContext.Vcs.pVc;
  299. if (pVc == NULL) {
  300. Status = STATUS_CONNECTION_DISCONNECTED;
  301. }
  302. if ((Status == STATUS_SUCCESS) &&
  303. (pVc->State == SMBCE_VC_STATE_MULTIPLEXED)) {
  304. Status = RxCeSend(
  305. &pVc->RxCeVc,
  306. SendOptions,
  307. pSmbMdl,
  308. SendLength,
  309. pSendCompletionContext);
  310. if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
  311. Status = STATUS_PENDING;
  312. // The underlying connection engine assumes the responsibility of
  313. // invoking the send complete handler from this point.
  314. fInvokeSendCompleteHandler = FALSE;
  315. }
  316. } else {
  317. RxDbgTrace(0, Dbg, ("VctTranceive: Disconnected connection detected\n"));
  318. Status = STATUS_CONNECTION_DISCONNECTED;
  319. }
  320. } else {
  321. // The server entry is not valid ...
  322. Status = STATUS_CONNECTION_DISCONNECTED;
  323. }
  324. }
  325. if (Status != STATUS_PENDING) {
  326. RxDbgTrace(0, Dbg, ("VctTranceive: Return Status %lx\n",Status));
  327. }
  328. // There are instances in which the send was aborted even before the underlying
  329. // transport was invoked. In such cases the appropriate send complete handler
  330. // needs to be called so that the associated exchange can be finalized.
  331. if (fInvokeSendCompleteHandler) {
  332. NTSTATUS LocalStatus;
  333. LocalStatus = SmbCeSendCompleteInd(
  334. pServerEntry,
  335. pSendCompletionContext,
  336. Status);
  337. RxDbgTrace(0, Dbg, ("VctTranceive: Send Complete Handler Return Status %lx\n",LocalStatus));
  338. }
  339. return Status;
  340. }
  341. NTSTATUS
  342. VctReceive(
  343. PSMBCE_SERVER_TRANSPORT pTransport,
  344. PSMBCEDB_SERVER_ENTRY pServerEntry,
  345. PSMB_EXCHANGE pExchange)
  346. /*++
  347. Routine Description:
  348. This routine transmits/receives a SMB for a give exchange
  349. Arguments:
  350. pTransport - the server transport
  351. pServerEntry - the server entry
  352. pExchange - the exchange instance issuing this SMB.
  353. Return Value:
  354. STATUS_PENDING - the request has been queued
  355. Other Status codes correspond to error situations.
  356. --*/
  357. {
  358. NTSTATUS Status = STATUS_SUCCESS;
  359. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  360. PSMBCE_VC pVc;
  361. PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
  362. PAGED_CODE();
  363. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  364. pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  365. pVc = pExchange->SmbCeContext.TransportContext.Vcs.pVc;
  366. // Ensure that the connection is still active before satisfying the request.
  367. if (SmbCeIsEntryInUse(&pServerEntry->Header) &&
  368. (pVc != NULL)) {
  369. Status = STATUS_SUCCESS;
  370. } else {
  371. // The server entry is not valid ...
  372. Status = STATUS_CONNECTION_DISCONNECTED;
  373. }
  374. return Status;
  375. }
  376. NTSTATUS
  377. VctSend(
  378. PSMBCE_SERVER_TRANSPORT pTransport,
  379. PSMBCEDB_SERVER_ENTRY pServerEntry,
  380. ULONG SendOptions,
  381. PMDL pSmbMdl,
  382. ULONG SendLength,
  383. PVOID pSendCompletionContext)
  384. /*++
  385. Routine Description:
  386. This routine opens/creates a server entry in the connection engine database
  387. Arguments:
  388. pTransport - the server transport
  389. pServer - the recepient server
  390. SendOptions - options for send
  391. pSmbMdl - the SMB that needs to be sent.
  392. SendLength - length of data to be sent
  393. pSendCompletionContext - the send completion context
  394. Return Value:
  395. STATUS_SUCCESS - the send was successful.
  396. STATUS_PENDING - the send has been queued
  397. Other Status codes correspond to error situations.
  398. --*/
  399. {
  400. NTSTATUS Status = STATUS_CONNECTION_DISCONNECTED;
  401. PSMBCE_VC pVc;
  402. PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
  403. BOOLEAN fInvokeSendCompleteHandler = TRUE;
  404. PAGED_CODE();
  405. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  406. pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  407. pVc = VctSelectMultiplexedVcEntry(pVcTransport);
  408. if (pVc != NULL) {
  409. if (pVc->State == SMBCE_VC_STATE_MULTIPLEXED) {
  410. Status = RxCeSend(
  411. &pVc->RxCeVc,
  412. SendOptions,
  413. pSmbMdl,
  414. SendLength,
  415. pSendCompletionContext);
  416. if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
  417. // The underlying connection engine assumes the responsibility of
  418. // invoking the send complete handler from this point.
  419. fInvokeSendCompleteHandler = FALSE;
  420. }
  421. }
  422. }
  423. if (!NT_SUCCESS(Status)) {
  424. RxDbgTrace(0, Dbg, ("VctSend: RxCeSend returned %lx\n",Status));
  425. }
  426. // There are instances in which the send was aborted even before the underlying
  427. // transport was invoked. In such cases the appropriate send complete handler
  428. // needs to be called so that the associated exchange can be finalized.
  429. if (fInvokeSendCompleteHandler) {
  430. NTSTATUS LocalStatus;
  431. LocalStatus = SmbCeSendCompleteInd(
  432. pServerEntry,
  433. pSendCompletionContext,
  434. Status);
  435. RxDbgTrace(0, Dbg, ("VctTranceive: Send Complete Handler Return Status %lx\n",LocalStatus));
  436. }
  437. return Status;
  438. }
  439. NTSTATUS
  440. VctSendDatagram(
  441. PSMBCE_SERVER_TRANSPORT pTransport,
  442. PSMBCEDB_SERVER_ENTRY pServerEntry,
  443. ULONG SendOptions,
  444. PMDL pSmbMdl,
  445. ULONG SendLength,
  446. PVOID pSendCompletionContext)
  447. /*++
  448. Routine Description:
  449. This routine opens/creates a server entry in the connection engine database
  450. Arguments:
  451. pTransport - the server transport
  452. pServer - the recepient server
  453. SendOptions - options for send
  454. pSmbMdl - the SMB that needs to be sent.
  455. SendLength - length of data to be sent
  456. pSendCompletionContext - the send completion context
  457. Return Value:
  458. STATUS_SUCCESS - the server call construction has been finalized.
  459. STATUS_PENDING - the open involves network traffic and the exchange has been
  460. queued for notification ( pServerPointer is set to NULL)
  461. Other Status codes correspond to error situations.
  462. --*/
  463. {
  464. PAGED_CODE();
  465. return STATUS_NOT_IMPLEMENTED;
  466. }
  467. PSMBCE_VC
  468. VctSelectVc(
  469. PSMBCE_SERVER_VC_TRANSPORT pVcTransport,
  470. BOOLEAN fMultiplexed)
  471. /*++
  472. Routine Description:
  473. This routine embodies the logic for the selection of a VC on which the SMB exchange
  474. will transpire
  475. Arguments:
  476. pVcTransport - the transport structure
  477. fMultiplexed - the desired mode
  478. Return Value:
  479. a referenced VC entry if successful otherwise NULL
  480. --*/
  481. {
  482. NTSTATUS Status;
  483. PSMBCE_VC pVc = NULL;
  484. ULONG VcIndex,NumberOfActiveVcs = 0;
  485. SMBCE_VC_STATE DesiredState;
  486. PAGED_CODE();
  487. if (fMultiplexed) {
  488. RxDbgTrace(0, Dbg, ("VctSelectVc: Referencing Multiplexed entry\n"));
  489. DesiredState = SMBCE_VC_STATE_MULTIPLEXED;
  490. } else {
  491. RxDbgTrace(0, Dbg, ("VctSelectVc: Referencing Raw entry\n"));
  492. DesiredState = SMBCE_VC_STATE_RAW;
  493. }
  494. // Acquire the resource
  495. SmbCeAcquireResource();
  496. // Choose the first VC that can support multiplexed requests
  497. for (VcIndex = 0; VcIndex < pVcTransport->MaximumNumberOfVCs; VcIndex++) {
  498. PSMBCE_VC pTempVc = &pVcTransport->Vcs[VcIndex];
  499. NumberOfActiveVcs++;
  500. if (pTempVc->State == SMBCE_VC_STATE_MULTIPLEXED) {
  501. if (DesiredState == SMBCE_VC_STATE_MULTIPLEXED) {
  502. pVc = pTempVc;
  503. break;
  504. } else {
  505. // If the current number of active references to a VC is zero, it can
  506. // be transformed into the raw mode.
  507. if (VctUpdateVcState(pTempVc,SMBCE_VC_STATE_RAW)) {
  508. pVc = pTempVc;
  509. break;
  510. } else {
  511. NumberOfActiveVcs++;
  512. }
  513. }
  514. }
  515. }
  516. if (pVc == NULL) {
  517. // Check if it is O.K. to add VCs to this connection. Currently the server
  518. // implementation supports only one VC per connection. Therefore if an
  519. // active VC exists which has been grabbed for raw mode use an error is returned.
  520. // Subsequently when the server is upgraded to handle multiple VCs the logic
  521. // for adding a new VC will be implemented as part of this routine.
  522. }
  523. if (pVc != NULL) {
  524. VctReferenceVc(pVc);
  525. }
  526. // release the resource
  527. SmbCeReleaseResource();
  528. return pVc;
  529. }
  530. NTSTATUS
  531. VctInitializeExchange(
  532. PSMBCE_SERVER_TRANSPORT pTransport,
  533. PSMB_EXCHANGE pExchange)
  534. /*++
  535. Routine Description:
  536. This routine initializes the transport information pertinent to a exchange
  537. Arguments:
  538. pTransport - the transport structure
  539. pExchange - the exchange instance
  540. Return Value:
  541. STATUS_SUCCESS -
  542. Other Status codes correspond to error situations.
  543. --*/
  544. {
  545. PSMBCEDB_SERVER_ENTRY pServerEntry;
  546. PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
  547. PAGED_CODE();
  548. pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  549. ASSERT(pExchange->SmbCeContext.TransportContext.Vcs.pVc == NULL);
  550. pExchange->SmbCeContext.TransportContext.Vcs.pVc
  551. = VctSelectMultiplexedVcEntry(pVcTransport);
  552. if (pExchange->SmbCeContext.TransportContext.Vcs.pVc == NULL) {
  553. RxDbgTrace(0, Dbg, ("VctInitializeExchange: Unsuccessful\n"));
  554. return STATUS_CONNECTION_DISCONNECTED;
  555. } else {
  556. RxDbgTrace(0, Dbg, ("VctInitializeExchange: Successful\n"));
  557. return STATUS_SUCCESS;
  558. }
  559. }
  560. NTSTATUS
  561. VctUninitializeExchange(
  562. PSMBCE_SERVER_TRANSPORT pTransport,
  563. PSMB_EXCHANGE pExchange)
  564. /*++
  565. Routine Description:
  566. This routine uninitializes the transport information pertinent to a exchange
  567. Arguments:
  568. pExchange - the exchange instance
  569. Return Value:
  570. STATUS_SUCCESS -
  571. Other Status codes correspond to error situations.
  572. --*/
  573. {
  574. PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
  575. PAGED_CODE();
  576. pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  577. RxDbgTrace(0, Dbg, ("VctUninitializeExchange: Successful\n"));
  578. if (pExchange->SmbCeContext.TransportContext.Vcs.pVc != NULL) {
  579. VctDereferenceVc(pExchange->SmbCeContext.TransportContext.Vcs.pVc);
  580. }
  581. pExchange->SmbCeContext.TransportContext.Vcs.pVc = NULL;
  582. return STATUS_SUCCESS;
  583. }
  584. NTSTATUS
  585. VctIndReceive(
  586. IN PVOID pEventContext,
  587. IN PRXCE_VC pVc,
  588. IN ULONG ReceiveFlags,
  589. IN ULONG BytesIndicated,
  590. IN ULONG BytesAvailable,
  591. OUT ULONG *pBytesTaken,
  592. IN PVOID pTsdu, // pointer describing this TSDU, typically a lump of bytes
  593. OUT PMDL *pDataBufferPointer, // the buffer in which data is to be copied.
  594. OUT PULONG pDataBufferSize // amount of data to copy
  595. )
  596. /*++
  597. Routine Description:
  598. This routine handles the receive indication for SMB's along all vcs in a connection to a
  599. server.
  600. Arguments:
  601. pEventContext - the server entry
  602. hVc - the Vc on which the SMB has been received
  603. ReceiveFlags - options for receive
  604. BytesIndicated - the bytes that are present in the indication.
  605. BytesAvailable - the total data available
  606. pTsdu - the data
  607. pDataBufferPointer - the buffer for copying the data not indicated.
  608. pDataBufferSize - the length of the buffer
  609. Return Value:
  610. STATUS_SUCCESS -
  611. Other Status codes correspond to error situations.
  612. --*/
  613. {
  614. NTSTATUS Status;
  615. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
  616. Status = SmbCeReceiveInd(
  617. pServerEntry,
  618. BytesIndicated,
  619. BytesAvailable,
  620. pBytesTaken,
  621. pTsdu,
  622. pDataBufferPointer,
  623. pDataBufferSize,
  624. ReceiveFlags);
  625. return Status;
  626. }
  627. NTSTATUS
  628. VctIndDataReady(
  629. IN PVOID pEventContext,
  630. IN PMDL pBuffer,
  631. IN ULONG DataSize,
  632. IN NTSTATUS CopyDataStatus
  633. )
  634. /*++
  635. Routine Description:
  636. This routine handles the indication when the requested data has been copied
  637. Arguments:
  638. pEventContext - the server instance
  639. pBuffer - the buffer being returned
  640. DataSize - the amount of data copied in bytes
  641. CopyDataStatus - CopyDataStatus
  642. Return Value:
  643. STATUS_SUCCESS - the server call construction has been finalized.
  644. Other Status codes correspond to error situations.
  645. --*/
  646. {
  647. NTSTATUS Status;
  648. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
  649. Status = SmbCeDataReadyInd(
  650. pServerEntry,
  651. pBuffer,
  652. DataSize,
  653. CopyDataStatus);
  654. return STATUS_SUCCESS;
  655. }
  656. NTSTATUS
  657. VctIndDisconnect(
  658. IN PVOID pEventContext,
  659. IN PRXCE_VC pRxCeVc,
  660. IN int DisconnectDataLength,
  661. IN PVOID DisconnectData,
  662. IN int DisconnectInformationLength,
  663. IN PVOID DisconnectInformation,
  664. IN ULONG DisconnectFlags
  665. )
  666. /*++
  667. Routine Description:
  668. This routine handles the disconnect indication for a VC.
  669. Arguments:
  670. pEventContext - the server instance
  671. hVc - the virtual circuit
  672. DisconnectDataLength -
  673. DisconnectData -
  674. DisconnectInformationLength -
  675. DisconnectInformation -
  676. DisconnectFlags -
  677. Return Value:
  678. STATUS_SUCCESS - the disconnect indication has been handled
  679. --*/
  680. {
  681. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
  682. PSMBCEDB_SERVER_ENTRY pListEntry;
  683. PSMBCE_VC pVc;
  684. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  685. PSMB_EXCHANGE pExchange;
  686. PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
  687. BOOLEAN fValidServerEntry = FALSE;
  688. BOOLEAN OutstandingWorkItem;
  689. // Traverse the list of server entries to ensure that the disconnect was on a
  690. // valid server entry. If it is not on a valid server entry ignore it.
  691. SmbCeAcquireSpinLock();
  692. pListEntry = SmbCeGetFirstServerEntry();
  693. while (pListEntry != NULL) {
  694. if (pListEntry == pServerEntry) {
  695. // The invalidation needs to hold onto an extra reference to avoid
  696. // race conditions which could lead to premature destruction of
  697. // this server entry.
  698. SmbCeReferenceServerEntry(pServerEntry);
  699. fValidServerEntry = TRUE;
  700. break;
  701. }
  702. pListEntry = SmbCeGetNextServerEntry(pListEntry);
  703. }
  704. if (fValidServerEntry) {
  705. pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
  706. if (pVcTransport != NULL) {
  707. ULONG VcIndex;
  708. for (VcIndex = 0; VcIndex < pVcTransport->MaximumNumberOfVCs; VcIndex++) {
  709. pVc = &pVcTransport->Vcs[VcIndex];
  710. if (&pVc->RxCeVc == pRxCeVc) {
  711. VctUpdateVcStateLite(pVc,SMBCE_VC_STATE_DISCONNECTED);
  712. pVc->Status = STATUS_CONNECTION_DISCONNECTED;
  713. break;
  714. }
  715. }
  716. }
  717. OutstandingWorkItem = pServerEntry->DisconnectWorkItemOutstanding;
  718. // OK to unconditionally set to TRUE
  719. pServerEntry->DisconnectWorkItemOutstanding = TRUE;
  720. }
  721. // Release the resource
  722. SmbCeReleaseSpinLock();
  723. if (fValidServerEntry) {
  724. RxDbgTrace(0,Dbg,("@@@@@@ Disconnect Indication for %lx @@@@@\n",pServerEntry));
  725. InterlockedIncrement(&MRxSmbStatistics.ServerDisconnects);
  726. // Update the Server entry if this is the only VC associated with the transport.
  727. SmbCeTransportDisconnectIndicated(pServerEntry);
  728. // only dereference if necessary (we might already have an outstanding request)
  729. if(OutstandingWorkItem == FALSE ) {
  730. InitializeListHead(&pServerEntry->WorkQueueItemForDisconnect.List);
  731. RxPostToWorkerThread(
  732. MRxSmbDeviceObject,
  733. CriticalWorkQueue,
  734. &pServerEntry->WorkQueueItemForDisconnect,
  735. SmbCepDereferenceServerEntry,
  736. pServerEntry);
  737. }
  738. RxDbgTrace(0, Dbg, ("VctIndDisconnect: Processing Disconnect indication on VC entry %lx\n",pVc));
  739. }
  740. return STATUS_SUCCESS;
  741. }
  742. NTSTATUS
  743. VctIndError(
  744. IN PVOID pEventContext,
  745. IN PRXCE_VC pRxCeVc,
  746. IN NTSTATUS IndicatedStatus
  747. )
  748. /*++
  749. Routine Description:
  750. This routine handles the error indication
  751. Arguments:
  752. pEventContext - the server instance
  753. pRxCeVc - the RxCe virtual circuit
  754. Status - the error
  755. Return Value:
  756. STATUS_SUCCESS
  757. --*/
  758. {
  759. NTSTATUS Status;
  760. ULONG VcIndex;
  761. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
  762. PSMBCE_VC pVc;
  763. PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
  764. // Acquire the resource
  765. SmbCeAcquireSpinLock();
  766. // Map the RXCE vc handle to the appropriate SMBCE entry and get the request
  767. // list associated with it.
  768. for (VcIndex = 0; VcIndex < pVcTransport->MaximumNumberOfVCs; VcIndex++) {
  769. pVc = &pVcTransport->Vcs[VcIndex];
  770. if (&pVc->RxCeVc == pRxCeVc) {
  771. VctUpdateVcStateLite(pVc,SMBCE_VC_STATE_DISCONNECTED);
  772. pVc->Status = IndicatedStatus;
  773. break;
  774. }
  775. }
  776. // Release the resource
  777. SmbCeReleaseSpinLock();
  778. RxDbgTrace(0, Dbg, ("VctIndError: Processing Error indication on VC entry %lx\n",pVc));
  779. Status = SmbCeErrorInd(
  780. pServerEntry,
  781. IndicatedStatus);
  782. return Status;
  783. }
  784. NTSTATUS
  785. VctIndEndpointError(
  786. IN PVOID pEventContext,
  787. IN NTSTATUS IndicatedStatus
  788. )
  789. /*++
  790. Routine Description:
  791. This routine handles the error indication
  792. Arguments:
  793. pEventContext - the server instance
  794. Status - the error
  795. Return Value:
  796. STATUS_SUCCESS
  797. --*/
  798. {
  799. PAGED_CODE();
  800. return STATUS_SUCCESS;
  801. }
  802. NTSTATUS
  803. VctIndSendPossible(
  804. IN PVOID pEventContext, // the event context.
  805. IN PRXCE_VC pRxCeVc,
  806. IN ULONG BytesAvailable
  807. )
  808. /*++
  809. Routine Description:
  810. This routine handles the error indication
  811. Arguments:
  812. pEventContext - the server instance
  813. hVc - the VC instance
  814. BytesAvailable - the number of bytes that can be sent
  815. Return Value:
  816. STATUS_SUCCESS
  817. --*/
  818. {
  819. PAGED_CODE();
  820. return STATUS_SUCCESS;
  821. }
  822. NTSTATUS
  823. VctIndReceiveDatagram(
  824. IN PVOID pRxCeEventContext, // the event context
  825. IN int SourceAddressLength, // length of the originator of the datagram
  826. IN PVOID SourceAddress, // string describing the originator of the datagram
  827. IN int OptionsLength, // options for the receive
  828. IN PVOID Options, //
  829. IN ULONG ReceiveDatagramFlags, //
  830. IN ULONG BytesIndicated, // number of bytes this indication
  831. IN ULONG BytesAvailable, // number of bytes in complete Tsdu
  832. OUT ULONG *BytesTaken, // number of bytes used
  833. IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
  834. OUT PMDL *pDataBufferPointer, // the buffer in which data is to be copied.
  835. OUT PULONG pDataBufferSize // amount of data to copy
  836. )
  837. {
  838. return STATUS_SUCCESS;
  839. }
  840. NTSTATUS
  841. VctIndSendComplete(
  842. IN PVOID pEventContext,
  843. IN PRXCE_VC pRxCeVc,
  844. IN PVOID pCompletionContext,
  845. IN NTSTATUS SendCompletionStatus
  846. )
  847. /*++
  848. Routine Description:
  849. This routine handles the send complete indication for asynchronous sends
  850. Arguments:
  851. pEventContext - the server instance
  852. pRxCeVc - the RxCe VC instance
  853. pCompletionContext - the context for identifying the send request
  854. SendCompletionStatus - the send completion status
  855. Return Value:
  856. STATUS_SUCCESS always ..
  857. --*/
  858. {
  859. NTSTATUS Status;
  860. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
  861. Status = SmbCeSendCompleteInd(
  862. pServerEntry,
  863. pCompletionContext,
  864. SendCompletionStatus);
  865. return Status;
  866. }
  867. //
  868. // Static dispatch vectors for Virtual Circuit based transports
  869. //
  870. RXCE_ADDRESS_EVENT_HANDLER
  871. MRxSmbVctAddressEventHandler = {
  872. VctIndEndpointError,
  873. VctIndReceiveDatagram,
  874. VctIndDataReady,
  875. VctIndSendPossible,
  876. NULL
  877. };
  878. RXCE_CONNECTION_EVENT_HANDLER
  879. MRxSmbVctConnectionEventHandler = {
  880. VctIndDisconnect,
  881. VctIndError,
  882. VctIndReceive,
  883. VctIndReceiveDatagram,
  884. VctIndReceive,
  885. VctIndSendPossible,
  886. VctIndDataReady,
  887. VctIndSendComplete
  888. };
  889. TRANSPORT_DISPATCH_VECTOR
  890. MRxSmbVctTransportDispatch = {
  891. VctSend,
  892. VctSendDatagram,
  893. VctTranceive,
  894. VctReceive,
  895. NULL,
  896. VctInitializeExchange,
  897. VctUninitializeExchange,
  898. VctTearDownServerTransport,
  899. VctInitiateDisconnect
  900. };
  901. typedef enum _RXCE_VC_FUNCTION_CODE {
  902. VcConnect,
  903. VcDisconnect
  904. } RXCE_VC_FUNCTION_CODE, *PRXCE_VC_FUNCTION_CODE;
  905. typedef struct _RXCE_VC_CONNECT_CONTEXT {
  906. RXCE_VC_FUNCTION_CODE FunctionCode;
  907. PRX_WORKERTHREAD_ROUTINE pRoutine;
  908. PSMBCEDB_SERVER_ENTRY pServerEntry;
  909. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext;
  910. PSMBCE_SERVER_TRANSPORT pServerTransport;
  911. NTSTATUS Status;
  912. KEVENT SyncEvent;
  913. } RXCE_VC_CONNECT_CONTEXT, *PRXCE_VC_CONNECT_CONTEXT;
  914. NTSTATUS
  915. VctCompleteInitialization(
  916. PSMBCEDB_SERVER_ENTRY pServerEntry,
  917. PSMBCE_TRANSPORT pTransport,
  918. PSMBCE_SERVER_VC_TRANSPORT pVcTransport)
  919. /*++
  920. Routine Description:
  921. This routine initializes the transport information corresponding to a server
  922. Arguments:
  923. pServerEntry - the server entry instance in the database
  924. Return Value:
  925. STATUS_SUCCESS - the server transport construction has been finalized.
  926. Other Status codes correspond to error situations.
  927. Notes:
  928. The remote address can be either deduced from the information in the Rx Context
  929. or a NETBIOS address needs to be built from the server name.
  930. This transport address is used subsequently to establish the connection.
  931. --*/
  932. {
  933. NTSTATUS Status;
  934. PSMBCE_VC pVc;
  935. RXCE_CONNECTION_INFO ConnectionInfo;
  936. RXCE_TRANSPORT_PROVIDER_INFO ProviderInfo;
  937. PAGED_CODE();
  938. pVc = &pVcTransport->Vcs[0];
  939. // Query the transport information ...
  940. Status = RxCeQueryInformation(
  941. &pVc->RxCeVc,
  942. RxCeTransportProviderInformation,
  943. &ProviderInfo,
  944. sizeof(ProviderInfo));
  945. if (NT_SUCCESS(Status)) {
  946. pVcTransport->MaximumSendSize = MIN( ProviderInfo.MaxSendSize,
  947. MAXIMUM_PARTIAL_BUFFER_SIZE );
  948. } else {
  949. // CODE.IMPROVMENT - fix constant below to a #define, also is the
  950. // value correct?
  951. ASSERT( 1024 <= MAXIMUM_PARTIAL_BUFFER_SIZE );
  952. pVcTransport->MaximumSendSize = 1024;
  953. }
  954. // Query the connection information ....
  955. Status = RxCeQueryInformation(
  956. &pVc->RxCeVc,
  957. RxCeConnectionEndpointInformation,
  958. &ConnectionInfo,
  959. sizeof(ConnectionInfo));
  960. if (NT_SUCCESS(Status)) {
  961. // The setting of the delay parameter is an important heuristic
  962. // that determines how quickly and how often timeouts occur. As
  963. // a first cut a very conservative estimate for the time has been
  964. // choosen, i.e., double the time required to transmit a 64 k packet.
  965. // This parameter should be fine tuned.
  966. pVcTransport->Delay.QuadPart = (-ConnectionInfo.Delay.QuadPart) +
  967. (-ConnectionInfo.Delay.QuadPart);
  968. if (ConnectionInfo.Throughput.LowPart != 0) {
  969. pVcTransport->Delay.QuadPart +=
  970. (MAX_SMB_PACKET_SIZE/ConnectionInfo.Throughput.LowPart) * 1000 * 10000;
  971. }
  972. RxDbgTrace( 0, Dbg, ("Connection delay set to %ld 100ns ticks\n",pVcTransport->Delay.LowPart));
  973. pVcTransport->pDispatchVector = &MRxSmbVctTransportDispatch;
  974. pVcTransport->MaximumNumberOfVCs = 1;
  975. pVc->State = SMBCE_VC_STATE_MULTIPLEXED;
  976. pVcTransport->State = SMBCEDB_ACTIVE;
  977. } else {
  978. RxDbgTrace(0, Dbg, ("VctInitialize : RxCeQueryInformation returned %lx\n",Status));
  979. }
  980. if (NT_SUCCESS(Status)) {
  981. pVcTransport->pTransport = pTransport;
  982. } else {
  983. RxDbgTrace(0, Dbg, ("VctInitialize : Connection Initialization Failed %lx\n",Status));
  984. }
  985. return Status;
  986. }
  987. NTSTATUS
  988. VctUninitialize(
  989. PVOID pTransport)
  990. /*++
  991. Routine Description:
  992. This routine uninitializes the transport instance
  993. Arguments:
  994. pVcTransport - the VC transport instance
  995. Return Value:
  996. STATUS_SUCCESS - the server transport construction has been uninitialzied.
  997. Other Status codes correspond to error situations.
  998. Notes:
  999. --*/
  1000. {
  1001. NTSTATUS Status = STATUS_SUCCESS;
  1002. ULONG VcIndex;
  1003. PSMBCE_VC pVc;
  1004. PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  1005. ULONG TransportFlags;
  1006. PAGED_CODE();
  1007. // The spinlock needs to be acquired for manipulating the list of Vcs because of
  1008. // indications that will be processed till the appropriate RXCE data structures are
  1009. // dismantled
  1010. for (VcIndex = 0; VcIndex < pVcTransport->MaximumNumberOfVCs; VcIndex++) {
  1011. pVc = &pVcTransport->Vcs[VcIndex];
  1012. // Assert the fact that the request list associated with the VC is empty.
  1013. // Tear down the VC entry
  1014. Status = RxCeTearDownVC(&pVc->RxCeVc);
  1015. ASSERT(Status == STATUS_SUCCESS);
  1016. }
  1017. // Tear down the connection endpoint ..
  1018. Status = RxCeTearDownConnection(&pVcTransport->RxCeConnection);
  1019. ASSERT(Status == STATUS_SUCCESS);
  1020. RxDbgTrace(0, Dbg, ("VctUninitialize : RxCeDisconnect returned %lx\n",Status));
  1021. // Dereference the underlying transport
  1022. if (pVcTransport->pTransport != NULL) {
  1023. SmbCeDereferenceTransport(pVcTransport->pTransport);
  1024. }
  1025. ASSERT((pVcTransport->Vcs[0].RxCeVc.hEndpoint == INVALID_HANDLE_VALUE) ||
  1026. (pVcTransport->Vcs[0].RxCeVc.hEndpoint == NULL));
  1027. ASSERT(pVcTransport->Vcs[0].RxCeVc.pEndpointFileObject == NULL);
  1028. // Free up the transport entry
  1029. RxFreePool(pVcTransport);
  1030. return Status;
  1031. }
  1032. NTSTATUS
  1033. VctpTranslateNetbiosNameToIpAddress(
  1034. IN OEM_STRING *pName,
  1035. OUT ULONG *pIpAddress
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine converts ascii ipaddr (11.101.4.25) into a ULONG. This is
  1040. based on the inet_addr code in winsock
  1041. Arguments:
  1042. pName - the string containing the ipaddress
  1043. Return Value:
  1044. the ipaddress as a ULONG if it's a valid ipaddress. Otherwise, 0.
  1045. Notes:
  1046. The body of this routine has been borrowed fron NetBt.
  1047. --*/
  1048. {
  1049. NTSTATUS Status;
  1050. PCHAR pStr;
  1051. int i;
  1052. int len, fieldLen;
  1053. int fieldsDone;
  1054. ULONG IpAddress;
  1055. BYTE ByteVal;
  1056. PCHAR pIpPtr;
  1057. BOOLEAN fDotFound;
  1058. BOOLEAN fieldOk;
  1059. PAGED_CODE();
  1060. Status = STATUS_INVALID_ADDRESS_COMPONENT;
  1061. if (pName->Length > NETBIOS_NAME_LEN) {
  1062. return Status;
  1063. }
  1064. pStr = pName->Buffer;
  1065. len = 0;
  1066. pIpPtr = (PCHAR)&IpAddress;
  1067. pIpPtr += 3; // so that we store in network order
  1068. fieldsDone=0;
  1069. //
  1070. // the 11.101.4.25 format can be atmost 15 chars, and pName is guaranteed
  1071. // to be at least 16 chars long (how convenient!!). Convert the string to
  1072. // a ULONG.
  1073. //
  1074. while(len < NETBIOS_NAME_LEN)
  1075. {
  1076. fieldLen=0;
  1077. fieldOk = FALSE;
  1078. ByteVal = 0;
  1079. fDotFound = FALSE;
  1080. //
  1081. // This loop traverses each of the four fields (max len of each
  1082. // field is 3, plus 1 for the '.'
  1083. //
  1084. while (fieldLen < 4)
  1085. {
  1086. if (*pStr >='0' && *pStr <='9')
  1087. {
  1088. ByteVal = (ByteVal*10) + (*pStr - '0');
  1089. fieldOk = TRUE;
  1090. }
  1091. else if (*pStr == '.' || *pStr == ' ' || *pStr == '\0')
  1092. {
  1093. *pIpPtr = ByteVal;
  1094. pIpPtr--;
  1095. fieldsDone++;
  1096. if (*pStr == '.')
  1097. fDotFound = TRUE;
  1098. // if we got a space or 0, assume it's the 4th field
  1099. if (*pStr == ' ' || *pStr == '\0')
  1100. {
  1101. break;
  1102. }
  1103. }
  1104. // unacceptable char: can't be ipaddr
  1105. else
  1106. {
  1107. return(Status);
  1108. }
  1109. pStr++;
  1110. len++;
  1111. fieldLen++;
  1112. // if we found the dot, we are done with this field: go to the next one
  1113. if (fDotFound)
  1114. break;
  1115. }
  1116. // this field wasn't ok (e.g. "11.101..4" or "11.101.4." etc.)
  1117. if (!fieldOk)
  1118. {
  1119. return(Status);
  1120. }
  1121. // if we are done with all 4 fields, we are done with the outer loop too
  1122. if ( fieldsDone == 4)
  1123. break;
  1124. if (!fDotFound)
  1125. {
  1126. return(Status);
  1127. }
  1128. }
  1129. //
  1130. // make sure the remaining chars are spaces or 0's (i.e. don't allow
  1131. // 11.101.4.25xyz to succeed)
  1132. //
  1133. for (i=len; i<NETBIOS_NAME_LEN; i++, pStr++)
  1134. {
  1135. if (*pStr != ' ' && *pStr != '\0')
  1136. {
  1137. return(Status);
  1138. }
  1139. }
  1140. *pIpAddress = IpAddress;
  1141. return( STATUS_SUCCESS );
  1142. }
  1143. ULONG
  1144. VctComputeTransportAddressSize(
  1145. IN PUNICODE_STRING pServerName)
  1146. /*++
  1147. Routine Description:
  1148. This routine takes a computer name (PUNICODE_STRING) and computes the size of the
  1149. TRANSPORT_ADDRESSS buffer required to connect to it.
  1150. Arguments:
  1151. IN PUNICODE_STRING Name - Supplies the name to put into the transport
  1152. Return Value:
  1153. size of the buffer.
  1154. Notes:
  1155. The compound transport address passed to the transports consists of two
  1156. TDI_NETBIOS_EX_ADDRESSes and a TDI_NETBIOS_ADDRESS. The two NETBIOS_EX addresses refer
  1157. to the two different endpoints registered by the server, i.e., *SMBSERVER and
  1158. the Server name padded upto NETBIOS_NAME_LEN with blanks. The order in which
  1159. the two NETBIOS_EX addresses are constructed depend upon the length of the server
  1160. name. If it is greater than NETBIOS_NAME_LEN *SMBSERVER is the first enpoint
  1161. and vice versa
  1162. --*/
  1163. {
  1164. ULONG NetbiosAddressLength,NetbiosExAddressLength,NetbiosUnicodeExAddressLength,TransportAddressSize;
  1165. ULONG OemServerNameLength;
  1166. PAGED_CODE();
  1167. OemServerNameLength = RtlUnicodeStringToOemSize(pServerName);
  1168. NetbiosAddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  1169. if( OemServerNameLength > NETBIOS_NAME_LEN ) {
  1170. NetbiosAddressLength += OemServerNameLength - NETBIOS_NAME_LEN;
  1171. }
  1172. NetbiosExAddressLength = FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) +
  1173. NetbiosAddressLength;
  1174. NetbiosUnicodeExAddressLength = FIELD_OFFSET(TDI_ADDRESS_NETBIOS_UNICODE_EX,RemoteNameBuffer) +
  1175. pServerName->Length +
  1176. DNS_NAME_BUFFER_LENGTH * sizeof(WCHAR);
  1177. TransportAddressSize = FIELD_OFFSET(TRANSPORT_ADDRESS,Address) +
  1178. 3 * FIELD_OFFSET(TA_ADDRESS,Address) +
  1179. NetbiosAddressLength +
  1180. 2 * NetbiosExAddressLength +
  1181. NetbiosUnicodeExAddressLength;
  1182. return TransportAddressSize;
  1183. }
  1184. NTSTATUS
  1185. VctBuildTransportAddress (
  1186. IN PTRANSPORT_ADDRESS pTransportAddress,
  1187. IN ULONG TransportAddressLength,
  1188. IN PUNICODE_STRING pServerName,
  1189. OUT PULONG pServerIpAddress
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. This routine takes a computer name (PUNICODE_STRING) and converts it into an
  1194. acceptable form for passing in as transport address.
  1195. Arguments:
  1196. pTransportAddress - Supplies the structure to fill in
  1197. TransportAddressLength - Supplies the length of the buffer at TransportAddress
  1198. pServerName - Supplies the name to put into the transport
  1199. pServerNameIsInIpAddressFormat = Server Name is of the dotted IP address kind
  1200. Return Value:
  1201. None.
  1202. Notes:
  1203. The compound transport address passed to the transports consists of two
  1204. TDI_NETBIOS_EX_ADDRESSes and a TDI_NETBIOS_ADDRESS. The two NETBIOS_EX addresses refer
  1205. to the two different endpoints registered by the server, i.e., *SMBSERVER and
  1206. the Server name padded upto NETBIOS_NAME_LEN with blanks. The order in which
  1207. the two NETBIOS_EX addresses are constructed depend upon the length of the server
  1208. name. If it is greater than NETBIOS_NAME_LEN *SMBSERVER is the first enpoint
  1209. and vice versa
  1210. The WINS database can be inconsistent for extended periods of time. In order to
  1211. account for this inconsistency on NETBIOS names and DNS names we will not
  1212. issue the address for *SMBSERVER. This will be revisited when we have a better
  1213. mechanism for identifying/authenticating the server and the client machine to each other.
  1214. --*/
  1215. {
  1216. OEM_STRING OemServerName;
  1217. NTSTATUS Status;
  1218. PTDI_ADDRESS_NETBIOS_EX pTdiNetbiosExAddress;
  1219. PTDI_ADDRESS_NETBIOS pTdiNetbiosAddress;
  1220. PTA_ADDRESS pFirstNetbiosExAddress,pSecondNetbiosExAddress,pNetbiosAddress,pNetbiosUnicodeExAddress;
  1221. PTDI_ADDRESS_NETBIOS_UNICODE_EX pTdiNetbiosUnicodeExAddress;
  1222. PCHAR FirstEndpointName,SecondEndpointName;
  1223. CHAR EndpointNameBuffer[NETBIOS_NAME_LEN];
  1224. WCHAR UnicodeEndpointNameBuffer[NETBIOS_NAME_LEN];
  1225. USHORT NetbiosAddressLength,NetbiosExAddressLength;
  1226. USHORT NetbiosAddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1227. ULONG ComponentLength;
  1228. ULONG RemoteIpAddress;
  1229. BOOLEAN ServerNameIsInIpAddressForm;
  1230. PAGED_CODE();
  1231. if (TransportAddressLength < VctComputeTransportAddressSize(pServerName)) {
  1232. return STATUS_BUFFER_OVERFLOW;
  1233. }
  1234. if (pServerName->Length > DNS_MAX_NAME_LENGTH) {
  1235. return STATUS_BAD_NETWORK_PATH;
  1236. }
  1237. pFirstNetbiosExAddress = &pTransportAddress->Address[0];
  1238. pTdiNetbiosExAddress = (PTDI_ADDRESS_NETBIOS_EX)pFirstNetbiosExAddress->Address;
  1239. pTdiNetbiosExAddress->NetbiosAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
  1240. OemServerName.Length = pServerName->Length;
  1241. OemServerName.MaximumLength = OemServerName.Length + 1;
  1242. OemServerName.Buffer = pTdiNetbiosExAddress->NetbiosAddress.NetbiosName;
  1243. Status = RtlUpcaseUnicodeStringToOemString(&OemServerName, pServerName, FALSE);
  1244. if( !NT_SUCCESS( Status ) ) {
  1245. //return STATUS_BAD_NETWORK_PATH;
  1246. OemServerName.Length = 0;
  1247. }
  1248. if (OemServerName.Length < NETBIOS_NAME_LEN) {
  1249. RtlCopyMemory( &OemServerName.Buffer[ OemServerName.Length ],
  1250. " ",
  1251. NETBIOS_NAME_LEN - OemServerName.Length
  1252. );
  1253. OemServerName.Length = NETBIOS_NAME_LEN;
  1254. }
  1255. Status = VctpTranslateNetbiosNameToIpAddress(&OemServerName,&RemoteIpAddress);
  1256. if (Status == STATUS_SUCCESS) {
  1257. if ((RemoteIpAddress == 0) || (RemoteIpAddress == 0xffffffff)) {
  1258. // If the server name is a valid IP address and matches with one of the two
  1259. // broadcast addresses used by IP turn back the request.
  1260. return STATUS_INVALID_ADDRESS_COMPONENT;
  1261. }
  1262. *pServerIpAddress = RemoteIpAddress;
  1263. ServerNameIsInIpAddressForm = TRUE;
  1264. } else {
  1265. *pServerIpAddress = 0;
  1266. ServerNameIsInIpAddressForm = FALSE;
  1267. }
  1268. NetbiosAddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  1269. if( OemServerName.Length > NETBIOS_NAME_LEN ) {
  1270. NetbiosAddressLength += OemServerName.Length - NETBIOS_NAME_LEN;
  1271. }
  1272. NetbiosExAddressLength = (USHORT)(FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) +
  1273. NetbiosAddressLength);
  1274. pFirstNetbiosExAddress->AddressLength = NetbiosExAddressLength;
  1275. pFirstNetbiosExAddress->AddressType = TDI_ADDRESS_TYPE_NETBIOS_EX;
  1276. #if 0
  1277. // This arm of the code will be activated and the other arm deactivated when we have
  1278. // mutual authenitication between server and client machines in NT5.0
  1279. if (ServerNameIsInIpAddressForm) {
  1280. pTransportAddress->TAAddressCount = 2;
  1281. pNetbiosAddress = (PTA_ADDRESS)((PCHAR)pFirstNetbiosExAddress +
  1282. FIELD_OFFSET(TA_ADDRESS,Address) +
  1283. NetbiosExAddressLength);
  1284. FirstEndpointName = SMBSERVER_LOCAL_ENDPOINT_NAME;
  1285. } else {
  1286. pTransportAddress->TAAddressCount = 3;
  1287. pSecondNetbiosExAddress = (PTA_ADDRESS)((PCHAR)pFirstNetbiosExAddress +
  1288. FIELD_OFFSET(TA_ADDRESS,Address) +
  1289. NetbiosExAddressLength);
  1290. pNetbiosAddress = (PTA_ADDRESS)((PCHAR)pSecondNetbiosExAddress +
  1291. FIELD_OFFSET(TA_ADDRESS,Address) +
  1292. NetbiosExAddressLength);
  1293. // Scan the server name till the first delimiter (DNS delimiter .) and form
  1294. // the endpoint name by padding the remaining name with blanks.
  1295. RtlCopyMemory(
  1296. EndpointNameBuffer,
  1297. OemServerName.Buffer,
  1298. NETBIOS_NAME_LEN);
  1299. ComponentLength = 0;
  1300. while (ComponentLength < NETBIOS_NAME_LEN) {
  1301. if (EndpointNameBuffer[ComponentLength] == '.') {
  1302. break;
  1303. }
  1304. ComponentLength++;
  1305. }
  1306. if (ComponentLength == NETBIOS_NAME_LEN) {
  1307. EndpointNameBuffer[NETBIOS_NAME_LEN - 1] = ' ';
  1308. } else {
  1309. RtlCopyMemory(&EndpointNameBuffer[ComponentLength],
  1310. " ",
  1311. NETBIOS_NAME_LEN - ComponentLength);
  1312. }
  1313. FirstEndpointName = EndpointNameBuffer;
  1314. SecondEndpointName = SMBSERVER_LOCAL_ENDPOINT_NAME;
  1315. }
  1316. #else
  1317. pTransportAddress->TAAddressCount = 3;
  1318. pNetbiosAddress = (PTA_ADDRESS)((PCHAR)pFirstNetbiosExAddress +
  1319. FIELD_OFFSET(TA_ADDRESS,Address) +
  1320. NetbiosExAddressLength);
  1321. if (ServerNameIsInIpAddressForm) {
  1322. FirstEndpointName = SMBSERVER_LOCAL_ENDPOINT_NAME;
  1323. } else {
  1324. // Scan the server name till the first delimiter (DNS delimiter .) and form
  1325. // the endpoint name by padding the remaining name with blanks.
  1326. RtlCopyMemory(
  1327. EndpointNameBuffer,
  1328. OemServerName.Buffer,
  1329. NETBIOS_NAME_LEN);
  1330. ComponentLength = 0;
  1331. while (ComponentLength < NETBIOS_NAME_LEN) {
  1332. if (EndpointNameBuffer[ComponentLength] == '.') {
  1333. break;
  1334. }
  1335. ComponentLength++;
  1336. }
  1337. if (ComponentLength == NETBIOS_NAME_LEN) {
  1338. EndpointNameBuffer[NETBIOS_NAME_LEN - 1] = ' ';
  1339. } else {
  1340. RtlCopyMemory(&EndpointNameBuffer[ComponentLength],
  1341. " ",
  1342. NETBIOS_NAME_LEN - ComponentLength);
  1343. }
  1344. FirstEndpointName = EndpointNameBuffer;
  1345. }
  1346. #endif
  1347. // Copy the first endpoint name
  1348. RtlCopyMemory(
  1349. pTdiNetbiosExAddress->EndpointName,
  1350. FirstEndpointName,
  1351. NETBIOS_NAME_LEN);
  1352. #if 0
  1353. // This will be activated alongwith the other code when mutual authentication is
  1354. // in place
  1355. if (!ServerNameIsInIpAddressForm) {
  1356. // The same NETBIOS_EX address needs to be duplicated with a different endpoint name
  1357. // for the second TA_ADDRESS.
  1358. RtlCopyMemory(
  1359. pSecondNetbiosExAddress,
  1360. pFirstNetbiosExAddress,
  1361. (FIELD_OFFSET(TA_ADDRESS,Address) + NetbiosExAddressLength));
  1362. RtlCopyMemory(
  1363. ((PCHAR)pSecondNetbiosExAddress +
  1364. FIELD_OFFSET(TA_ADDRESS,Address) +
  1365. FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,EndpointName)),
  1366. SecondEndpointName,
  1367. NETBIOS_NAME_LEN);
  1368. }
  1369. #else
  1370. //ASSERT(pTransportAddress->TAAddressCount == 2);
  1371. #endif
  1372. // The Netbios address associated with the first NETBIOS_EX address is the last netbios
  1373. // address that is passed in.
  1374. RtlCopyMemory(
  1375. ((PCHAR)pNetbiosAddress),
  1376. &NetbiosAddressLength,
  1377. sizeof(USHORT));
  1378. RtlCopyMemory(
  1379. ((PCHAR)pNetbiosAddress + FIELD_OFFSET(TA_ADDRESS,AddressType)),
  1380. &NetbiosAddressType,
  1381. sizeof(USHORT));
  1382. RtlCopyMemory(
  1383. ((PCHAR)pNetbiosAddress + FIELD_OFFSET(TA_ADDRESS,Address)),
  1384. &pTdiNetbiosExAddress->NetbiosAddress,
  1385. NetbiosAddressLength);
  1386. // Unicode Netbios name
  1387. pNetbiosUnicodeExAddress = (PTA_ADDRESS)((PCHAR)pNetbiosAddress +
  1388. FIELD_OFFSET(TA_ADDRESS,Address) +
  1389. NetbiosAddressLength);
  1390. pNetbiosUnicodeExAddress->AddressLength = (USHORT)(FIELD_OFFSET(TDI_ADDRESS_NETBIOS_UNICODE_EX,RemoteNameBuffer) +
  1391. DNS_NAME_BUFFER_LENGTH * sizeof(WCHAR));
  1392. pNetbiosUnicodeExAddress->AddressType = TDI_ADDRESS_TYPE_NETBIOS_UNICODE_EX;
  1393. pTdiNetbiosUnicodeExAddress = (PTDI_ADDRESS_NETBIOS_UNICODE_EX)pNetbiosUnicodeExAddress->Address;
  1394. pTdiNetbiosUnicodeExAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
  1395. pTdiNetbiosUnicodeExAddress->NameBufferType = NBT_READWRITE;
  1396. pTdiNetbiosUnicodeExAddress->EndpointName.Length = (NETBIOS_NAME_LEN)*sizeof(WCHAR);
  1397. pTdiNetbiosUnicodeExAddress->EndpointName.MaximumLength = (NETBIOS_NAME_LEN+1)*sizeof(WCHAR);
  1398. pTdiNetbiosUnicodeExAddress->EndpointName.Buffer = (PWSTR)pTdiNetbiosUnicodeExAddress->EndpointBuffer;
  1399. pTdiNetbiosUnicodeExAddress->RemoteName.Length = pServerName->Length;
  1400. pTdiNetbiosUnicodeExAddress->RemoteName.MaximumLength = DNS_NAME_BUFFER_LENGTH*sizeof(WCHAR);
  1401. pTdiNetbiosUnicodeExAddress->RemoteName.Buffer = (PWSTR)pTdiNetbiosUnicodeExAddress->RemoteNameBuffer;
  1402. if (pTdiNetbiosUnicodeExAddress->RemoteName.MaximumLength > pServerName->Length) {
  1403. ComponentLength = pServerName->Length;
  1404. } else {
  1405. ComponentLength = pTdiNetbiosUnicodeExAddress->RemoteName.MaximumLength;
  1406. }
  1407. RtlCopyMemory(
  1408. pTdiNetbiosUnicodeExAddress->RemoteNameBuffer,
  1409. pServerName->Buffer,
  1410. ComponentLength);
  1411. if (ServerNameIsInIpAddressForm) {
  1412. RtlCopyMemory(
  1413. pTdiNetbiosUnicodeExAddress->EndpointBuffer,
  1414. SMBSERVER_LOCAL_ENDPOINT_NAME_UNICODE,
  1415. NETBIOS_NAME_LEN);
  1416. } else {
  1417. // Scan the server name till the first delimiter (DNS delimiter .) and form
  1418. // the endpoint name by padding the remaining name with blanks.
  1419. RtlCopyMemory(
  1420. pTdiNetbiosUnicodeExAddress->EndpointBuffer,
  1421. L" ",
  1422. NETBIOS_NAME_LEN*sizeof(WCHAR));
  1423. if (pTdiNetbiosUnicodeExAddress->EndpointName.Length > pServerName->Length) {
  1424. ComponentLength = pServerName->Length;
  1425. } else {
  1426. ComponentLength = pTdiNetbiosUnicodeExAddress->EndpointName.Length;
  1427. }
  1428. RtlCopyMemory(
  1429. pTdiNetbiosUnicodeExAddress->EndpointBuffer,
  1430. pServerName->Buffer,
  1431. ComponentLength);
  1432. ComponentLength = 0;
  1433. while (ComponentLength < NETBIOS_NAME_LEN) {
  1434. if (pTdiNetbiosUnicodeExAddress->EndpointBuffer[ComponentLength] == L'.') {
  1435. break;
  1436. }
  1437. ComponentLength++;
  1438. }
  1439. if (ComponentLength == NETBIOS_NAME_LEN) {
  1440. pTdiNetbiosUnicodeExAddress->EndpointBuffer[NETBIOS_NAME_LEN - 1] = ' ';
  1441. } else {
  1442. RtlCopyMemory(&pTdiNetbiosUnicodeExAddress->EndpointBuffer[ComponentLength],
  1443. L" ",
  1444. (NETBIOS_NAME_LEN-ComponentLength)*sizeof(WCHAR));
  1445. }
  1446. }
  1447. //DbgPrint("Build TA %lx %lx %lx\n",pFirstNetbiosExAddress,pNetbiosAddress,pNetbiosUnicodeExAddress);
  1448. return STATUS_SUCCESS;
  1449. }
  1450. typedef struct _SMBCE_VC_CONNECTION_COMPLETION_CONTEXT {
  1451. RXCE_CONNECTION_COMPLETION_CONTEXT;
  1452. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  1453. PSMBCE_TRANSPORT pTransport;
  1454. PSMBCE_SERVER_VC_TRANSPORT pServerTransport;
  1455. ULONG TransportAddressLength;
  1456. PTRANSPORT_ADDRESS pTransportAddress;
  1457. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext;
  1458. } SMBCE_VC_CONNECTION_COMPLETION_CONTEXT,
  1459. *PSMBCE_VC_CONNECTION_COMPLETION_CONTEXT;
  1460. NTSTATUS
  1461. VctpCreateConnectionCallback(
  1462. IN OUT PRXCE_CONNECTION_COMPLETION_CONTEXT pContext)
  1463. /*++
  1464. Routine Description:
  1465. This is the connection callback routine initiated when the underlying
  1466. transports have completed initialization
  1467. Arguments:
  1468. pCOntext = the connection completion context
  1469. Notes:
  1470. --*/
  1471. {
  1472. NTSTATUS Status;
  1473. PSMBCE_VC_CONNECTION_COMPLETION_CONTEXT pVcCompletionContext;
  1474. PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pSmbCeContext;
  1475. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1476. PAGED_CODE();
  1477. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1478. pVcCompletionContext = (PSMBCE_VC_CONNECTION_COMPLETION_CONTEXT)pContext;
  1479. pSmbCeContext = pVcCompletionContext->pContext;
  1480. pServerEntry = pSmbCeContext->pServerEntry;
  1481. pSmbCeContext->Status = pVcCompletionContext->Status;
  1482. Status = pVcCompletionContext->Status;
  1483. if (Status == STATUS_SUCCESS) {
  1484. PTA_ADDRESS pTaAdress;
  1485. PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)pVcCompletionContext->pConnectionInformation->RemoteAddress;
  1486. LONG NoOfAddress;
  1487. if (pVcCompletionContext->pTransport == NULL) {
  1488. pVcCompletionContext->pTransport =
  1489. pVcCompletionContext->pTransportArray->SmbCeTransports[
  1490. pVcCompletionContext->AddressIndex];
  1491. SmbCeReferenceTransport(pVcCompletionContext->pTransport);
  1492. }
  1493. //DbgPrint("Remote address %lx \n",pVcCompletionContext->pConnectionInformation->RemoteAddress);
  1494. //DbgPrint("Number of TA returned %d %lx\n",pTransportAddress->TAAddressCount,pTransportAddress->Address);
  1495. pTaAdress = &pTransportAddress->Address[0];
  1496. for (NoOfAddress=0; NoOfAddress<pTransportAddress->TAAddressCount;NoOfAddress++) {
  1497. if (pTaAdress->AddressType == TDI_ADDRESS_TYPE_NETBIOS_UNICODE_EX) {
  1498. PTDI_ADDRESS_NETBIOS_UNICODE_EX pTdiNetbiosUnicodeExAddress;
  1499. pTdiNetbiosUnicodeExAddress = (PTDI_ADDRESS_NETBIOS_UNICODE_EX)pTaAdress->Address;
  1500. pTdiNetbiosUnicodeExAddress->EndpointName.Buffer = (PWSTR)pTdiNetbiosUnicodeExAddress->EndpointBuffer;
  1501. pTdiNetbiosUnicodeExAddress->RemoteName.Buffer = (PWSTR)pTdiNetbiosUnicodeExAddress->RemoteNameBuffer;
  1502. SmbCeAcquireResource();
  1503. if (pTdiNetbiosUnicodeExAddress->NameBufferType == NBT_WRITTEN) {
  1504. //DbgPrint("DNS name was returned from NetBT %wZ\n", &pTdiNetbiosUnicodeExAddress->RemoteName);
  1505. DWORD dwNewSize = pTdiNetbiosUnicodeExAddress->RemoteName.Length+2*sizeof(WCHAR);
  1506. // if old allocation is to small get rid of it
  1507. if(pServerEntry->DnsName.Buffer != NULL &&
  1508. dwNewSize > pServerEntry->DnsName.MaximumLength) {
  1509. RxFreePool(pServerEntry->DnsName.Buffer);
  1510. pServerEntry->DnsName.Buffer = NULL;
  1511. }
  1512. // make new allocation (if we don't already have one)
  1513. if(pServerEntry->DnsName.Buffer == NULL) {
  1514. pServerEntry->DnsName.Buffer = RxAllocatePoolWithTag(NonPagedPool, dwNewSize, MRXSMB_SERVER_POOLTAG);
  1515. }
  1516. if (pServerEntry->DnsName.Buffer != NULL) {
  1517. pServerEntry->DnsName.Length = pTdiNetbiosUnicodeExAddress->RemoteName.Length;
  1518. pServerEntry->DnsName.MaximumLength = pServerEntry->DnsName.Length+2*sizeof(WCHAR);
  1519. RtlCopyMemory(pServerEntry->DnsName.Buffer,
  1520. pTdiNetbiosUnicodeExAddress->RemoteNameBuffer,
  1521. pServerEntry->DnsName.Length);
  1522. } else {
  1523. Status = STATUS_INSUFFICIENT_RESOURCES;
  1524. }
  1525. } else {
  1526. //DbgPrint("DNS name was not returned from NetBT for %wZ\n", &pTdiNetbiosUnicodeExAddress->RemoteName);
  1527. if(pServerEntry->DnsName.Buffer != NULL) {
  1528. RxFreePool(pServerEntry->DnsName.Buffer);
  1529. pServerEntry->DnsName.Buffer = NULL;
  1530. }
  1531. }
  1532. SmbCeReleaseResource();
  1533. break;
  1534. } else {
  1535. //DbgPrint("TA %lx is not a NETBIOS_UNICODE_EX\n", pTaAdress);
  1536. pTaAdress = (PTA_ADDRESS)((PCHAR)pTaAdress +
  1537. FIELD_OFFSET(TA_ADDRESS,Address) +
  1538. pTaAdress->AddressLength);
  1539. }
  1540. }
  1541. if (Status == STATUS_SUCCESS) {
  1542. // The Server IP address is not known. Query the underlying
  1543. // transport for the remote transport address, i.e., NETBIOS
  1544. // name or IP address. This will be subsequently used to
  1545. // determine the VC number to be used in session setup and X for
  1546. // downlevel servers.
  1547. Status = RxCeQueryInformation(
  1548. pVcCompletionContext->pVc,
  1549. RxCeRemoteAddressInformation,
  1550. pVcCompletionContext->pTransportAddress,
  1551. pVcCompletionContext->TransportAddressLength);
  1552. }
  1553. if (Status == STATUS_SUCCESS) {
  1554. ULONG NumberOfAddresses;
  1555. USHORT AddressLength;
  1556. USHORT AddressType;
  1557. PBYTE pBuffer = (PBYTE)pVcCompletionContext->pTransportAddress;
  1558. // All Transports currently return a data structure in which
  1559. // the first four bytes are a ULONG which encodes the number
  1560. // of connections opened to the given remote address. The
  1561. // actual Transport address follows.
  1562. pBuffer += sizeof(ULONG);
  1563. // The buffer contains a TRANSPORT_ADDRESS, the first field
  1564. // of which is the count.
  1565. NumberOfAddresses = SmbGetUlong(pBuffer);
  1566. // This is followed by an array of variable length TA_ADDRESS
  1567. // structures. At this point pBuffer points to the first
  1568. // TA_ADDRESS.
  1569. pBuffer += sizeof(ULONG);
  1570. while (NumberOfAddresses-- > 0) {
  1571. AddressLength = SmbGetUshort(pBuffer);
  1572. pBuffer += sizeof(USHORT);
  1573. AddressType = SmbGetUshort(pBuffer);
  1574. if (AddressType != TDI_ADDRESS_TYPE_IP) {
  1575. // skip to the next TA_ADDRESS
  1576. pBuffer += AddressLength + sizeof(USHORT);
  1577. } else {
  1578. // Skip past the type field to position at the
  1579. // corresponding TDI_ADDRESS_IP structure
  1580. pBuffer += sizeof(USHORT);
  1581. // skip to the in_addr field
  1582. pBuffer += FIELD_OFFSET(TDI_ADDRESS_IP,in_addr);
  1583. // Extract the IP address
  1584. RtlCopyMemory(
  1585. &pServerEntry->Server.IpAddress,
  1586. pBuffer,
  1587. sizeof(ULONG));
  1588. break;
  1589. }
  1590. }
  1591. } else {
  1592. RxDbgTrace(0, Dbg, ("Remote Address Query returned %lx\n",Status));
  1593. }
  1594. if (NT_SUCCESS(Status)) {
  1595. Status = VctCompleteInitialization(
  1596. pServerEntry, // The server entry
  1597. pVcCompletionContext->pTransport, // the transport/address information
  1598. pVcCompletionContext->pServerTransport); // the server transport instance
  1599. }
  1600. if (NT_SUCCESS(Status)) {
  1601. pSmbCeContext->pTransport =
  1602. (PSMBCE_SERVER_TRANSPORT)pVcCompletionContext->pServerTransport;
  1603. pVcCompletionContext->pServerTransport = NULL;
  1604. pVcCompletionContext->pTransport = NULL;
  1605. }
  1606. pSmbCeContext->Status = Status;
  1607. } else {
  1608. SmbLogError(Status,
  1609. LOG,
  1610. VctpCreateConnectionCallback,
  1611. LOGULONG(Status)
  1612. LOGPTR(pServerEntry)
  1613. LOGUSTR(pServerEntry->Name));
  1614. }
  1615. if (!NT_SUCCESS(Status)) {
  1616. RxCeTearDownVC(pVcCompletionContext->pVc);
  1617. RxCeTearDownConnection(pVcCompletionContext->pConnection);
  1618. SmbCeDereferenceTransport(pVcCompletionContext->pTransport);
  1619. pVcCompletionContext->pTransport = NULL;
  1620. }
  1621. if (pVcCompletionContext->pTransportArray != NULL) {
  1622. SmbCeDereferenceTransportArray(pVcCompletionContext->pTransportArray);
  1623. }
  1624. if (pVcCompletionContext->pTransportAddress != NULL) {
  1625. RxFreePool(pVcCompletionContext->pTransportAddress);
  1626. }
  1627. if (pVcCompletionContext->pConnectionInformation != NULL) {
  1628. RxFreePool(pVcCompletionContext->pConnectionInformation);
  1629. }
  1630. ASSERT(pVcCompletionContext->pTransport == NULL);
  1631. if (pVcCompletionContext->pServerTransport != NULL) {
  1632. SmbMmFreeServerTransport(
  1633. (PSMBCE_SERVER_TRANSPORT)pVcCompletionContext->pServerTransport);
  1634. }
  1635. RxFreePool(pVcCompletionContext);
  1636. pSmbCeContext->State = SmbCeServerVcTransportConstructionEnd;
  1637. SmbCeConstructServerTransport(pSmbCeContext);
  1638. return STATUS_SUCCESS;
  1639. }
  1640. NTSTATUS
  1641. VctInstantiateServerTransport(
  1642. IN OUT PSMBCE_SERVER_TRANSPORT_CONSTRUCTION_CONTEXT pContext)
  1643. /*++
  1644. Routine Description:
  1645. This routine initializes the transport information corresponding to a server
  1646. Arguments:
  1647. pContext - the transport construction context
  1648. Return Value:
  1649. STATUS_PENDING - asynchronous construction has been initiated
  1650. Notes:
  1651. Currently, only connection oriented transports are handled. The current TDI
  1652. spec expects handles to be passed in as part of the connect request. This
  1653. implies that connect/reconnect/disconnect requests need to be issued from the
  1654. process which created the connection. In the case of the SMB mini rdr there
  1655. is no FSP associated with it ( threads are borrowed/commandeered ) from the
  1656. system process to do all the work. This is the reason for special casing VC
  1657. initialization into a separate routine. The server transport initialization
  1658. routine handles the other transport initialization and also provides the
  1659. context for VC initialization.
  1660. --*/
  1661. {
  1662. NTSTATUS Status = STATUS_PENDING;
  1663. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  1664. PAGED_CODE();
  1665. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1666. pTransportArray = SmbCeReferenceTransportArray();
  1667. if (pTransportArray == NULL) {
  1668. Status = STATUS_NETWORK_UNREACHABLE;
  1669. } else {
  1670. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1671. UNICODE_STRING ServerName;
  1672. PSMBCE_VC_CONNECTION_COMPLETION_CONTEXT pCompletionContext;
  1673. PRXCE_CONNECTION_INFORMATION InitialConnectionInformation = NULL;
  1674. ULONG ServerIpAddress;
  1675. pServerEntry = pContext->pServerEntry;
  1676. ServerName.Buffer = pServerEntry->Name.Buffer + 1;
  1677. ServerName.Length = pServerEntry->Name.Length - sizeof(WCHAR);
  1678. ServerName.MaximumLength = pServerEntry->Name.MaximumLength - sizeof(WCHAR);
  1679. pServerEntry->Server.IpAddress = 0;
  1680. pCompletionContext = (PSMBCE_VC_CONNECTION_COMPLETION_CONTEXT)
  1681. RxAllocatePoolWithTag(
  1682. NonPagedPool,
  1683. sizeof(SMBCE_VC_CONNECTION_COMPLETION_CONTEXT),
  1684. MRXSMB_VC_POOLTAG);
  1685. if (pCompletionContext != NULL) {
  1686. RtlZeroMemory(pCompletionContext,sizeof(SMBCE_VC_CONNECTION_COMPLETION_CONTEXT));
  1687. pCompletionContext->pContext = pContext;
  1688. pCompletionContext->TransportAddressLength = VctComputeTransportAddressSize(
  1689. &ServerName);
  1690. pCompletionContext->pTransportAddress = (PTRANSPORT_ADDRESS)
  1691. RxAllocatePoolWithTag(
  1692. NonPagedPool,
  1693. pCompletionContext->TransportAddressLength,
  1694. MRXSMB_VC_POOLTAG);
  1695. if (pCompletionContext->pTransportAddress == NULL) {
  1696. Status = STATUS_INSUFFICIENT_RESOURCES;
  1697. } else {
  1698. RtlZeroMemory(pCompletionContext->pTransportAddress,
  1699. pCompletionContext->TransportAddressLength);
  1700. Status = VctBuildTransportAddress(
  1701. pCompletionContext->pTransportAddress,
  1702. pCompletionContext->TransportAddressLength,
  1703. &ServerName,
  1704. &ServerIpAddress);
  1705. }
  1706. if (Status == STATUS_SUCCESS) {
  1707. pCompletionContext->pServerTransport = (PSMBCE_SERVER_VC_TRANSPORT)
  1708. SmbMmAllocateServerTransport(
  1709. SMBCE_STT_VC);
  1710. if (pCompletionContext->pServerTransport == NULL) {
  1711. Status = STATUS_INSUFFICIENT_RESOURCES;
  1712. } else {
  1713. pCompletionContext->pConnection =
  1714. &(pCompletionContext->pServerTransport->RxCeConnection);
  1715. pCompletionContext->pVc =
  1716. &(pCompletionContext->pServerTransport->Vcs[0].RxCeVc);
  1717. }
  1718. }
  1719. if (Status == STATUS_SUCCESS) {
  1720. InitialConnectionInformation = RxAllocatePoolWithTag(
  1721. NonPagedPool,
  1722. sizeof(RXCE_CONNECTION_INFORMATION),
  1723. MRXSMB_VC_POOLTAG);
  1724. if (InitialConnectionInformation == NULL) {
  1725. Status = STATUS_INSUFFICIENT_RESOURCES;
  1726. } else {
  1727. InitialConnectionInformation->UserDataLength = 0;
  1728. InitialConnectionInformation->OptionsLength = 0;
  1729. InitialConnectionInformation->RemoteAddressLength = pCompletionContext->TransportAddressLength;
  1730. InitialConnectionInformation->RemoteAddress = pCompletionContext->pTransportAddress;
  1731. }
  1732. }
  1733. if (Status == STATUS_SUCCESS) {
  1734. PSMBCE_TRANSPORT pTransport;
  1735. pCompletionContext->pTransport = NULL;
  1736. pCompletionContext->pTransportArray = pTransportArray;
  1737. pCompletionContext->pConnectionInformation = InitialConnectionInformation;
  1738. //DbgPrint("Remote address %lx \n",pCompletionContext->pConnectionInformation->RemoteAddress);
  1739. if (pServerEntry->PreferredTransport != NULL) {
  1740. pTransport = pServerEntry->PreferredTransport;
  1741. Status = RxCeBuildConnection(
  1742. &pTransport->RxCeAddress,
  1743. InitialConnectionInformation,
  1744. &MRxSmbVctConnectionEventHandler,
  1745. pServerEntry,
  1746. pCompletionContext->pConnection,
  1747. pCompletionContext->pVc);
  1748. if (Status == STATUS_SUCCESS) {
  1749. pCompletionContext->pTransport = pTransport;
  1750. SmbCeReferenceTransport(pTransport);
  1751. }
  1752. ASSERT(Status != STATUS_PENDING);
  1753. if (Status != STATUS_SUCCESS) {
  1754. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  1755. pServerEntry->PreferredTransport = NULL;
  1756. }
  1757. pCompletionContext->Status = Status;
  1758. VctpCreateConnectionCallback(
  1759. (PRXCE_CONNECTION_COMPLETION_CONTEXT)pCompletionContext);
  1760. Status = STATUS_PENDING;
  1761. } else {
  1762. Status = RxCeBuildConnectionOverMultipleTransports(
  1763. MRxSmbDeviceObject,
  1764. MRxSmbObeyBindingOrder ?
  1765. RxCeSelectBestSuccessfulTransport :
  1766. RxCeSelectFirstSuccessfulTransport,
  1767. pCompletionContext->pTransportArray->Count,
  1768. pCompletionContext->pTransportArray->LocalAddresses,
  1769. &ServerName,
  1770. InitialConnectionInformation,
  1771. &MRxSmbVctConnectionEventHandler,
  1772. pServerEntry,
  1773. VctpCreateConnectionCallback,
  1774. (PRXCE_CONNECTION_COMPLETION_CONTEXT)pCompletionContext);
  1775. // ASSERT(Status == STATUS_PENDING);
  1776. }
  1777. }
  1778. } else {
  1779. Status = STATUS_INSUFFICIENT_RESOURCES;
  1780. }
  1781. if (Status != STATUS_PENDING) {
  1782. if (pCompletionContext != NULL) {
  1783. if (pCompletionContext->pTransportAddress != NULL) {
  1784. RxFreePool(pCompletionContext->pTransportAddress);
  1785. }
  1786. if (pCompletionContext->pServerTransport != NULL) {
  1787. RxFreePool(pCompletionContext->pServerTransport);
  1788. }
  1789. RxFreePool(pCompletionContext);
  1790. }
  1791. if (InitialConnectionInformation != NULL) {
  1792. RxFreePool(InitialConnectionInformation);
  1793. }
  1794. SmbCeDereferenceTransportArray(pTransportArray);
  1795. }
  1796. }
  1797. if (Status != STATUS_PENDING) {
  1798. ASSERT(Status != STATUS_SUCCESS);
  1799. pContext->State = SmbCeServerVcTransportConstructionEnd;
  1800. pContext->Status = Status;
  1801. // Call the construct server transport routine to complete the construction
  1802. SmbCeConstructServerTransport(pContext);
  1803. Status = STATUS_PENDING;
  1804. }
  1805. return Status;
  1806. }
  1807. NTSTATUS
  1808. VctTearDownServerTransport(
  1809. PSMBCE_SERVER_TRANSPORT pServerTransport)
  1810. {
  1811. NTSTATUS Status;
  1812. PKEVENT pRundownEvent = pServerTransport->pRundownEvent;
  1813. PAGED_CODE();
  1814. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1815. Status = VctUninitialize(pServerTransport);
  1816. if (pRundownEvent != NULL) {
  1817. KeSetEvent(pRundownEvent, 0, FALSE );
  1818. }
  1819. return Status;
  1820. }
  1821. NTSTATUS
  1822. VctInitiateDisconnect(
  1823. PSMBCE_SERVER_TRANSPORT pServerTransport)
  1824. {
  1825. ULONG VcIndex;
  1826. PSMBCE_VC pVc;
  1827. PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerTransport;
  1828. ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
  1829. for (VcIndex = 0; VcIndex < pVcTransport->MaximumNumberOfVCs; VcIndex++) {
  1830. NTSTATUS Status;
  1831. pVc = &pVcTransport->Vcs[VcIndex];
  1832. Status = RxCeInitiateVCDisconnect(&pVc->RxCeVc);
  1833. if (Status != STATUS_SUCCESS) {
  1834. RxDbgTrace(0, Dbg, ("VctInitiateDisconnect: Disconnected Status %lxd\n",Status));
  1835. }
  1836. }
  1837. return STATUS_SUCCESS;
  1838. }
  1839. PFILE_OBJECT
  1840. SmbCepReferenceEndpointFileObject(
  1841. PSMBCE_SERVER_TRANSPORT pTransport)
  1842. /*++
  1843. Routine Description:
  1844. This routine returns the connection file object associated with
  1845. a transport
  1846. Arguments:
  1847. pTransport - the transport instance
  1848. Notes:
  1849. This routine currently returns this for VC transports. When we implement
  1850. other transports a suitable abstraction needs to be implemented
  1851. --*/
  1852. {
  1853. PFILE_OBJECT pEndpointFileObject = NULL;
  1854. PSMBCE_OBJECT_HEADER pHeader = (PSMBCE_OBJECT_HEADER)pTransport;
  1855. if ((pHeader != NULL) && (pHeader->ObjectType == SMBCE_STT_VC)) {
  1856. PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
  1857. pEndpointFileObject = pVcTransport->Vcs[0].RxCeVc.pEndpointFileObject;
  1858. if (pEndpointFileObject != NULL) {
  1859. ObReferenceObject(pEndpointFileObject);
  1860. }
  1861. }
  1862. return pEndpointFileObject;
  1863. }