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.

953 lines
25 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. sock.c
  5. Abstract:
  6. Pseudo-socket
  7. Author:
  8. Jiandong Ruan
  9. Revision History:
  10. Feb-14-2001 First functional version
  11. Feb-16-2001 Support IPv4
  12. --*/
  13. #include "precomp.h"
  14. #include "sock.tmh"
  15. NTSTATUS
  16. SmbOpenAddress(
  17. IN PUNICODE_STRING ucDevice,
  18. IN PSMB_IP_ADDRESS addr,
  19. IN USHORT port,
  20. IN OUT PSMB_TCP_ADDRESS context
  21. );
  22. NTSTATUS
  23. TdiOpenConnection(
  24. IN HANDLE hAddress,
  25. IN OUT PSMB_TCP_CONNECT Connect,
  26. IN PVOID ConnectionContext
  27. );
  28. NTSTATUS
  29. TdiAssociateConnection(
  30. IN PSMB_TCP_ADDRESS Address,
  31. IN PSMB_TCP_CONNECT Connect
  32. );
  33. NTSTATUS
  34. TdiSetEventHandler(
  35. PFILE_OBJECT FileObject,
  36. ULONG EventType,
  37. PVOID EventHandler,
  38. PVOID Context
  39. );
  40. #pragma alloc_text(PAGE, SmbOpenTcpAddress)
  41. #pragma alloc_text(PAGE, SmbOpenUdpAddress)
  42. #pragma alloc_text(PAGE, SmbOpenAddress)
  43. #pragma alloc_text(PAGE, SmbCloseAddress)
  44. #pragma alloc_text(PAGE, SmbSetTcpEventHandlers)
  45. #pragma alloc_text(PAGE, TdiAssociateConnection)
  46. #pragma alloc_text(PAGE, TdiOpenConnection)
  47. #pragma alloc_text(PAGE, TdiSetEventHandler)
  48. NTSTATUS
  49. SmbSynchTdiCompletion(
  50. IN PDEVICE_OBJECT DeviceObject,
  51. IN PIRP Irp,
  52. IN PVOID Context
  53. )
  54. /*++
  55. Routine Description:
  56. This routine doesn't free the IRP. It just signal an event to allow
  57. the synchronous part of the SMB driver to proceed.
  58. Arguments:
  59. Return Value:
  60. --*/
  61. {
  62. KeSetEvent((PKEVENT)Context, 0, FALSE);
  63. return STATUS_MORE_PROCESSING_REQUIRED;
  64. }
  65. NTSTATUS
  66. SubmitSynchTdiRequest (
  67. IN PFILE_OBJECT FileObject,
  68. IN PIRP Irp
  69. )
  70. /*++
  71. Routine Description:
  72. This routine submits a request to TDI and waits for it to complete.
  73. Arguments:
  74. IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
  75. IN PIRP Irp - TDI request to submit.
  76. Return Value:
  77. NTSTATUS - Final status of request.
  78. --*/
  79. {
  80. KEVENT Event;
  81. NTSTATUS status;
  82. PAGED_CODE();
  83. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  84. // set the address of the routine to be executed when the IRP
  85. // finishes. This routine signals the event and allows the code
  86. // below to continue (i.e. KeWaitForSingleObject)
  87. //
  88. IoSetCompletionRoutine(
  89. Irp,
  90. (PIO_COMPLETION_ROUTINE)SmbSynchTdiCompletion,
  91. &Event,
  92. TRUE,
  93. TRUE,
  94. TRUE
  95. );
  96. status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
  97. //
  98. // If it failed immediately, return now, otherwise wait.
  99. //
  100. if (!NT_SUCCESS(status)) {
  101. SmbPrint(SMB_TRACE_TCP, ("SubmitSynchTdiRequest: Failed to Submit Tdi Request, status = 0x%08lx\n", status));
  102. SmbTrace(SMB_TRACE_TCP, ("Failed to Submit Tdi Request, %!status!", status));
  103. return status;
  104. }
  105. if (status == STATUS_PENDING) {
  106. status = KeWaitForSingleObject (
  107. &Event,
  108. Executive,
  109. KernelMode,
  110. FALSE,
  111. NULL
  112. );
  113. if (status != STATUS_WAIT_0) {
  114. ASSERT(0);
  115. SmbTrace(SMB_TRACE_TCP, ("KeWaitForSingleObject return %!status!", status));
  116. return status;
  117. }
  118. status = Irp->IoStatus.Status;
  119. }
  120. SmbPrint(SMB_TRACE_TCP, ("SubmitSynchTdiRequest returns status = 0x%08lx\n", status));
  121. SmbTrace(SMB_TRACE_TCP, ("returns %!status!", status));
  122. return (status);
  123. }
  124. PVOID
  125. SmbPrepareTdiAddress(
  126. IN PSMB_IP_ADDRESS addr, // network order
  127. IN USHORT port, // network order
  128. OUT USHORT *pAddrSize
  129. )
  130. /*++
  131. Routine Description:
  132. This function set up an ipaddr in TDI format.
  133. Arguments:
  134. Return Value:
  135. --*/
  136. {
  137. PTA_IP6_ADDRESS pIP6Addr = NULL;
  138. PTA_IP_ADDRESS pIP4Addr = NULL;
  139. PVOID pAddr = NULL;
  140. USHORT IpAddrSize;
  141. if (addr->sin_family == SMB_AF_INET) {
  142. IpAddrSize = sizeof(TA_IP_ADDRESS);
  143. } else if (addr->sin_family == SMB_AF_INET6) {
  144. IpAddrSize = sizeof(TA_IP6_ADDRESS);
  145. } else {
  146. SmbTrace(SMB_TRACE_TCP, ("Invalid IP address family"));
  147. return NULL;
  148. }
  149. pAddr = ExAllocatePoolWithTag(NonPagedPool, IpAddrSize, 'jBMS');
  150. if(NULL == pAddr) {
  151. return NULL;
  152. }
  153. //
  154. // Setup the IP address
  155. //
  156. RtlZeroMemory(pAddr, IpAddrSize);
  157. if (addr->sin_family == SMB_AF_INET) {
  158. pIP4Addr = (PTA_IP_ADDRESS)pAddr;
  159. pIP4Addr->TAAddressCount = 1;
  160. pIP4Addr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  161. pIP4Addr->Address[0].AddressLength = sizeof(pIP4Addr->Address[0].Address[0]);
  162. pIP4Addr->Address[0].Address[0].sin_port = port;
  163. pIP4Addr->Address[0].Address[0].in_addr = addr->ip4.sin4_addr;
  164. } else {
  165. pIP6Addr = (PTA_IP6_ADDRESS)pAddr;
  166. pIP6Addr->TAAddressCount = 1;
  167. pIP6Addr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP6;
  168. pIP6Addr->Address[0].AddressLength = sizeof(pIP6Addr->Address[0].Address[0]);
  169. pIP6Addr->Address[0].Address[0].sin6_port = port;
  170. RtlCopyMemory(pIP6Addr->Address[0].Address[0].sin6_addr, addr->ip6.sin6_addr, sizeof(addr->ip6.sin6_addr));
  171. pIP6Addr->Address[0].Address[0].sin6_flowinfo = 0;
  172. pIP6Addr->Address[0].Address[0].sin6_scope_id = addr->ip6.sin6_scope_id;
  173. }
  174. *pAddrSize = IpAddrSize;
  175. return pAddr;
  176. }
  177. NTSTATUS
  178. SmbPrepareEaBuffer(
  179. IN PSMB_IP_ADDRESS addr,
  180. IN USHORT port,
  181. PFILE_FULL_EA_INFORMATION *pEaBuffer,
  182. USHORT *pEaBufferSize
  183. )
  184. {
  185. PTA_IP6_ADDRESS pIP6Addr = NULL;
  186. PTA_IP_ADDRESS pIP4Addr = NULL;
  187. PVOID pAddr = NULL;
  188. USHORT IpAddrSize;
  189. USHORT EaBufferSize;
  190. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  191. *pEaBuffer = NULL;
  192. *pEaBufferSize = 0;
  193. pAddr = SmbPrepareTdiAddress(addr, port, &IpAddrSize);
  194. if (NULL == pAddr) {
  195. return STATUS_NO_MEMORY;
  196. }
  197. //
  198. // Allocate Ea buffer for holding the TdiTransportAddress and the IP6 address
  199. //
  200. EaBufferSize = sizeof(FILE_FULL_EA_INFORMATION) +
  201. TDI_TRANSPORT_ADDRESS_LENGTH +
  202. IpAddrSize;
  203. EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, EaBufferSize, 'jBMS');
  204. if(NULL == EaBuffer) {
  205. ExFreePool(pAddr);
  206. return STATUS_NO_MEMORY;
  207. }
  208. //
  209. // Setup the ea buffer
  210. //
  211. EaBuffer->NextEntryOffset = 0;
  212. EaBuffer->Flags = 0;
  213. EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  214. EaBuffer->EaValueLength = IpAddrSize;
  215. RtlCopyMemory(EaBuffer->EaName, TdiTransportAddress, EaBuffer->EaNameLength + 1);
  216. RtlCopyMemory((PUCHAR)EaBuffer->EaName + EaBuffer->EaNameLength + 1, pAddr, IpAddrSize);
  217. ExFreePool(pAddr);
  218. *pEaBuffer = EaBuffer;
  219. *pEaBufferSize = EaBufferSize;
  220. return STATUS_SUCCESS;
  221. }
  222. NTSTATUS
  223. SmbOpenAddress(
  224. IN PUNICODE_STRING ucDevice,
  225. IN PSMB_IP_ADDRESS addr,
  226. IN USHORT port,
  227. IN OUT PSMB_TCP_ADDRESS context
  228. )
  229. /*++
  230. Routine Description:
  231. Open a Tcp/Udp address
  232. Arguments:
  233. ucDevice The device name of TCP or UDP
  234. addr The local address to be opened (network order)
  235. port The local port to be opened (network order)
  236. We will claim for exclusive ownership for a non-zero port
  237. This happens when SMB device open 445 port (for listening).
  238. For outbound connection request, SMB use 0 port which means
  239. TCP will pick up a proper port # for us.
  240. context The TCP context used to receive the opened address object
  241. Return Value:
  242. STATUS_SUCCES
  243. failed
  244. --*/
  245. {
  246. OBJECT_ATTRIBUTES AddrAttr = { 0 };
  247. NTSTATUS status = STATUS_SUCCESS;
  248. USHORT EaBufferSize = 0;
  249. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  250. IO_STATUS_BLOCK IoStatusBlock = { 0 };
  251. HANDLE AddrHandle = NULL;
  252. PFILE_OBJECT AddrFileObject = NULL;
  253. PAGED_CODE();
  254. if (context->AddressHandle || context->AddressObject) {
  255. ASSERT(0);
  256. return STATUS_INVALID_PARAMETER;
  257. }
  258. AddrHandle = NULL;
  259. AddrFileObject = NULL;
  260. status = SmbPrepareEaBuffer(addr, port, &EaBuffer, &EaBufferSize);
  261. BAIL_OUT_ON_ERROR(status);
  262. //
  263. // Open address with the transport
  264. //
  265. InitializeObjectAttributes(
  266. &AddrAttr,
  267. ucDevice,
  268. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  269. NULL,
  270. NULL
  271. );
  272. status = ZwCreateFile(
  273. &AddrHandle,
  274. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  275. &AddrAttr,
  276. &IoStatusBlock,
  277. NULL,
  278. FILE_ATTRIBUTE_NORMAL,
  279. (port)? 0: FILE_SHARE_READ | FILE_SHARE_WRITE, // Claim exclusive ownership for SMB port
  280. FILE_OPEN_IF,
  281. 0,
  282. EaBuffer,
  283. EaBufferSize
  284. );
  285. ExFreePool(EaBuffer);
  286. EaBuffer = NULL;
  287. SmbPrint(SMB_TRACE_TCP, ("ZwCreateFile returns status 0x%08lx\n", status));
  288. BAIL_OUT_ON_ERROR(status);
  289. status = IoStatusBlock.Status;
  290. BAIL_OUT_ON_ERROR(status);
  291. status = ObReferenceObjectByHandle(
  292. AddrHandle,
  293. 0,
  294. NULL,
  295. KernelMode,
  296. &AddrFileObject,
  297. NULL
  298. );
  299. BAIL_OUT_ON_ERROR(status);
  300. ObDereferenceObject(AddrFileObject);
  301. context->AddressHandle = AddrHandle;
  302. context->AddressObject = AddrFileObject;
  303. context->DeviceObject = IoGetRelatedDeviceObject(AddrFileObject);
  304. SmbTrace(SMB_TRACE_TCP, ("%!status!", status));
  305. return status;
  306. cleanup:
  307. if (NULL != EaBuffer) {
  308. ExFreePool(EaBuffer);
  309. EaBuffer = NULL;
  310. }
  311. if (AddrHandle) {
  312. ZwClose(AddrHandle);
  313. }
  314. SmbTrace(SMB_TRACE_TCP, ("%!status!", status));
  315. return status;
  316. }
  317. NTSTATUS
  318. SmbCloseAddress(
  319. IN OUT PSMB_TCP_ADDRESS context
  320. )
  321. {
  322. NTSTATUS status;
  323. PAGED_CODE();
  324. if (NULL == context->AddressHandle ||
  325. NULL == context->AddressObject ||
  326. NULL == context->DeviceObject) {
  327. ASSERT(0);
  328. return STATUS_INVALID_PARAMETER;
  329. }
  330. status = ZwClose(context->AddressHandle);
  331. if (status == STATUS_SUCCESS) {
  332. context->AddressHandle = NULL;
  333. context->AddressObject = NULL;
  334. context->DeviceObject = NULL;
  335. } else {
  336. ASSERT (0);
  337. }
  338. return status;
  339. }
  340. NTSTATUS
  341. SmbOpenTcpAddress(
  342. IN PSMB_IP_ADDRESS addr,
  343. IN USHORT port,
  344. IN OUT PSMB_TCP_ADDRESS context
  345. )
  346. {
  347. UNICODE_STRING ucName = { 0 };
  348. NTSTATUS status = STATUS_SUCCESS;
  349. NTSTATUS LocStatus = STATUS_SUCCESS;
  350. ULONG uIPv6ProtectionLevel = SmbCfg.uIPv6Protection;
  351. PAGED_CODE();
  352. if (addr->sin_family == SMB_AF_INET) {
  353. RtlInitUnicodeString(&ucName, DD_TCP_DEVICE_NAME);
  354. } else if (addr->sin_family == SMB_AF_INET6) {
  355. RtlInitUnicodeString(&ucName, DD_TCPV6_DEVICE_NAME);
  356. } else {
  357. return STATUS_INVALID_PARAMETER;
  358. }
  359. status = SmbOpenAddress(&ucName, addr, port, context);
  360. BAIL_OUT_ON_ERROR(status);
  361. if (addr->sin_family == SMB_AF_INET6) {
  362. LocStatus = SmbSetTcpInfo (
  363. context->AddressObject,
  364. CL_TL_ENTITY,
  365. INFO_CLASS_PROTOCOL,
  366. AO_OPTION_PROTECT,
  367. INFO_TYPE_ADDRESS_OBJECT,
  368. uIPv6ProtectionLevel
  369. );
  370. SmbTrace(SMB_TRACE_TCP, ("Set IPv6Protection Level %d on AddrOb %p %!status!",
  371. uIPv6ProtectionLevel, context->AddressObject, LocStatus));
  372. }
  373. cleanup:
  374. return status;
  375. }
  376. NTSTATUS
  377. SmbOpenUdpAddress(
  378. IN PSMB_IP_ADDRESS addr,
  379. IN USHORT port,
  380. IN OUT PSMB_TCP_ADDRESS context
  381. )
  382. /*++
  383. Routine Description:
  384. Arguments:
  385. Return Value:
  386. --*/
  387. {
  388. UNICODE_STRING ucName;
  389. NTSTATUS status;
  390. PAGED_CODE();
  391. if (addr->sin_family == SMB_AF_INET) {
  392. RtlInitUnicodeString(&ucName, DD_UDP_DEVICE_NAME);
  393. } else if (addr->sin_family == SMB_AF_INET6) {
  394. RtlInitUnicodeString(&ucName, DD_UDPV6_DEVICE_NAME);
  395. } else {
  396. return STATUS_INVALID_PARAMETER;
  397. }
  398. status = SmbOpenAddress(&ucName, addr, port, context);
  399. BAIL_OUT_ON_ERROR(status);
  400. cleanup:
  401. return status;
  402. }
  403. NTSTATUS
  404. SmbSetTcpEventHandlers(
  405. PFILE_OBJECT AddressObject,
  406. PVOID Context
  407. )
  408. {
  409. NTSTATUS status;
  410. PAGED_CODE();
  411. status = TdiSetEventHandler(
  412. AddressObject,
  413. TDI_EVENT_CONNECT,
  414. SmbTdiConnectHandler,
  415. Context
  416. );
  417. BAIL_OUT_ON_ERROR(status);
  418. status = TdiSetEventHandler(
  419. AddressObject,
  420. TDI_EVENT_DISCONNECT,
  421. SmbTdiDisconnectHandler,
  422. Context
  423. );
  424. BAIL_OUT_ON_ERROR(status);
  425. status = TdiSetEventHandler(
  426. AddressObject,
  427. TDI_EVENT_RECEIVE,
  428. SmbTdiReceiveHandler,
  429. Context
  430. );
  431. BAIL_OUT_ON_ERROR(status);
  432. cleanup:
  433. return status;
  434. }
  435. NTSTATUS
  436. TdiOpenConnection(
  437. IN HANDLE hAddress,
  438. IN OUT PSMB_TCP_CONNECT Connect,
  439. IN PVOID ConnectionContext
  440. )
  441. /*++
  442. Routine Description:
  443. Open a TCP connection.
  444. Arguments:
  445. Return Value:
  446. --*/
  447. {
  448. UNICODE_STRING RelativeDeviceName = { 0, 0, NULL };
  449. USHORT EaBufferSize;
  450. PFILE_FULL_EA_INFORMATION EaBuffer;
  451. OBJECT_ATTRIBUTES ObAttr;
  452. HANDLE ConnectHandle;
  453. PFILE_OBJECT ConnectObject;
  454. IO_STATUS_BLOCK IoStatusBlock;
  455. NTSTATUS status;
  456. ConnectHandle = NULL;
  457. EaBuffer = NULL;
  458. PAGED_CODE();
  459. //
  460. // Open the connection object with TCP
  461. //
  462. InitializeObjectAttributes(
  463. &ObAttr,
  464. &RelativeDeviceName,
  465. OBJ_KERNEL_HANDLE,
  466. hAddress, // Use a relative file handle
  467. NULL
  468. );
  469. EaBufferSize = sizeof(FILE_FULL_EA_INFORMATION) +
  470. TDI_CONNECTION_CONTEXT_LENGTH +
  471. sizeof(CONNECTION_CONTEXT);
  472. EaBuffer = (PFILE_FULL_EA_INFORMATION)
  473. ExAllocatePoolWithTag(NonPagedPool, EaBufferSize, 'xBMS');
  474. if (NULL == EaBuffer) {
  475. return STATUS_NO_MEMORY;
  476. }
  477. EaBuffer->NextEntryOffset = 0;
  478. EaBuffer->Flags = 0;
  479. EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  480. EaBuffer->EaValueLength = sizeof(CONNECTION_CONTEXT);
  481. RtlCopyMemory(EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1);
  482. ASSERT(sizeof(PVOID) == sizeof(CONNECTION_CONTEXT));
  483. RtlCopyMemory(
  484. (PUCHAR)EaBuffer->EaName + EaBuffer->EaNameLength + 1,
  485. &ConnectionContext,
  486. sizeof(CONNECTION_CONTEXT)
  487. );
  488. status = ZwCreateFile(
  489. &ConnectHandle,
  490. GENERIC_READ | GENERIC_WRITE,
  491. &ObAttr,
  492. &IoStatusBlock,
  493. NULL,
  494. FILE_ATTRIBUTE_NORMAL,
  495. 0,
  496. FILE_CREATE,
  497. 0,
  498. EaBuffer,
  499. EaBufferSize
  500. );
  501. ExFreePool(EaBuffer);
  502. EaBuffer = NULL;
  503. SmbPrint(SMB_TRACE_TCP, ("ZwCreateFile returns status 0x%08lx\n", status));
  504. BAIL_OUT_ON_ERROR(status);
  505. status = IoStatusBlock.Status;
  506. BAIL_OUT_ON_ERROR(status);
  507. status = ObReferenceObjectByHandle(
  508. ConnectHandle,
  509. 0,
  510. NULL,
  511. KernelMode,
  512. &ConnectObject,
  513. NULL
  514. );
  515. BAIL_OUT_ON_ERROR(status);
  516. ObDereferenceObject(ConnectObject);
  517. Connect->ConnectHandle = ConnectHandle;
  518. Connect->ConnectObject = ConnectObject;
  519. if (SmbCfg.EnableNagling) {
  520. status = SmbSetTcpInfo(
  521. ConnectObject,
  522. CO_TL_ENTITY,
  523. INFO_CLASS_PROTOCOL,
  524. TCP_SOCKET_NODELAY,
  525. INFO_TYPE_CONNECTION,
  526. FALSE
  527. );
  528. } else {
  529. status = SmbSetTcpInfo(
  530. ConnectObject,
  531. CO_TL_ENTITY,
  532. INFO_CLASS_PROTOCOL,
  533. TCP_SOCKET_NODELAY,
  534. INFO_TYPE_CONNECTION,
  535. TRUE
  536. );
  537. }
  538. if (STATUS_SUCCESS != status) {
  539. SmbPrint(SMB_TRACE_TCP, ("Nagling: <0x%x> EnableNagling=%d\n",
  540. status, SmbCfg.EnableNagling));
  541. SmbTrace(SMB_TRACE_TCP, ("Nagling: %!status! EnableNagling=%d",
  542. status, SmbCfg.EnableNagling));
  543. status = STATUS_SUCCESS;
  544. }
  545. return status;
  546. cleanup:
  547. if (NULL != EaBuffer) {
  548. ExFreePool(EaBuffer);
  549. EaBuffer = NULL;
  550. }
  551. if (ConnectHandle) {
  552. ZwClose(ConnectHandle);
  553. }
  554. return status;
  555. }
  556. NTSTATUS
  557. TdiAssociateConnection(
  558. IN PSMB_TCP_ADDRESS Address,
  559. IN PSMB_TCP_CONNECT Connect
  560. )
  561. {
  562. PIRP Irp;
  563. NTSTATUS status;
  564. PAGED_CODE();
  565. ASSERT(Address->DeviceObject == IoGetRelatedDeviceObject(Connect->ConnectObject));
  566. Irp = SmbAllocIrp(Address->DeviceObject->StackSize);
  567. if (Irp == NULL) {
  568. return STATUS_INSUFFICIENT_RESOURCES;
  569. }
  570. TdiBuildAssociateAddress(
  571. Irp,
  572. Address->DeviceObject,
  573. Connect->ConnectObject,
  574. NULL,
  575. NULL,
  576. Address->AddressHandle
  577. );
  578. status = SubmitSynchTdiRequest(Connect->ConnectObject, Irp);
  579. SmbFreeIrp(Irp);
  580. SmbTrace (SMB_TRACE_TCP, ("return %!status!", status));
  581. SmbPrint (SMB_TRACE_TCP, ("TdiAssociateConnection return 0x%08lx\n", status));
  582. return status;
  583. }
  584. NTSTATUS
  585. SmbOpenTcpConnection(
  586. IN PSMB_TCP_ADDRESS Address,
  587. IN OUT PSMB_TCP_CONNECT Connect,
  588. IN PVOID ConnectionContext
  589. )
  590. /*++
  591. Routine Description:
  592. Open a TCP connection and associate it with the Address
  593. Arguments:
  594. Return Value:
  595. --*/
  596. {
  597. NTSTATUS status;
  598. SMB_TCP_CONNECT LocalConnect;
  599. if (NULL == Connect || Connect->ConnectHandle || Connect->ConnectObject) {
  600. ASSERT (0);
  601. return STATUS_INVALID_PARAMETER;
  602. }
  603. if (NULL == Address->AddressHandle ||
  604. NULL == Address->AddressObject ||
  605. NULL == Address->DeviceObject) {
  606. ASSERT (0);
  607. return STATUS_INVALID_PARAMETER;
  608. }
  609. status = TdiOpenConnection(
  610. Address->AddressHandle,
  611. &LocalConnect,
  612. ConnectionContext
  613. );
  614. BAIL_OUT_ON_ERROR(status);
  615. status = TdiAssociateConnection(
  616. Address,
  617. &LocalConnect
  618. );
  619. if (status != STATUS_SUCCESS) {
  620. ZwClose(LocalConnect.ConnectHandle);
  621. } else {
  622. *Connect = LocalConnect;
  623. }
  624. cleanup:
  625. return status;
  626. }
  627. NTSTATUS
  628. SmbCloseTcpConnection(
  629. IN OUT PSMB_TCP_CONNECT Connect
  630. )
  631. {
  632. NTSTATUS status;
  633. if (NULL == Connect->ConnectHandle || NULL == Connect->ConnectObject) {
  634. ASSERT(0);
  635. return STATUS_INVALID_PARAMETER;
  636. }
  637. status = ZwClose(Connect->ConnectHandle);
  638. if (STATUS_SUCCESS == status) {
  639. Connect->ConnectHandle = NULL;
  640. Connect->ConnectObject = NULL;
  641. }
  642. return status;
  643. }
  644. NTSTATUS
  645. TdiConnectComplete (
  646. IN PDEVICE_OBJECT DeviceObject,
  647. IN PIRP Irp,
  648. IN PSMB_CONNECT_CONTEXT Context
  649. )
  650. {
  651. PSMB_CONNECT ConnectObject;
  652. ConnectObject = (PSMB_CONNECT)Context->ClientContext;
  653. ASSERT(Context->AsyncInternalContext);
  654. if (Context->AsyncInternalContext) {
  655. ExFreePool(Context->AsyncInternalContext);
  656. Context->AsyncInternalContext = NULL;
  657. }
  658. SmbTrace (SMB_TRACE_CONNECT, ("pIrp %p complete with %!status! info=%d",
  659. Irp, Irp->IoStatus.Status, (ULONG)(Irp->IoStatus.Information)));
  660. Context->status = Irp->IoStatus.Status;
  661. Context->Completion((PSMB_ASYNC_CONTEXT)Context);
  662. //
  663. // We're actully using the client's IRP. The Context->Completion will complete it.
  664. // Don't allow IO manager to proceed.
  665. //
  666. return STATUS_MORE_PROCESSING_REQUIRED;
  667. }
  668. void
  669. SmbAsyncConnect(
  670. IN PSMB_IP_ADDRESS ipaddr,
  671. IN USHORT port,
  672. IN PSMB_CONNECT_CONTEXT Context
  673. )
  674. {
  675. PIRP Irp = NULL;
  676. PDEVICE_OBJECT DeviceObject = NULL;
  677. PSMB_CONNECT ConnectObject = NULL;
  678. PTDI_CONNECTION_INFORMATION SendInfo = NULL;
  679. PTRANSPORT_ADDRESS pAddr = NULL;
  680. USHORT IpAddrSize = 0;
  681. NTSTATUS status = STATUS_SUCCESS;
  682. #if DBG
  683. if (ipaddr->sin_family == SMB_AF_INET6) {
  684. CHAR target_ip[40];
  685. inet_ntoa6(target_ip, 40, &ipaddr->ip6);
  686. SmbPrint(SMB_TRACE_CALL, ("SmbAsyncConnect %s:%d\n", target_ip, ntohs(port)));
  687. }
  688. #endif
  689. ConnectObject = (PSMB_CONNECT)Context->ClientContext;
  690. //
  691. // Use the client's IRP so that the client can cancel it
  692. //
  693. Irp = ConnectObject->PendingIRPs[SMB_PENDING_CONNECT];
  694. if (NULL == Irp) {
  695. ASSERT(0);
  696. SmbTrace(SMB_TRACE_CONNECT, ("Internal Error: Expect a non-NULL Pending Connect Irp"));
  697. Context->status = STATUS_INTERNAL_ERROR;
  698. Context->Completion((PSMB_ASYNC_CONTEXT)Context);
  699. return;
  700. }
  701. pAddr = SmbPrepareTdiAddress(ipaddr, port, &IpAddrSize);
  702. if (pAddr == NULL) {
  703. SmbTrace(SMB_TRACE_CONNECT, ("cannot prepare TA_IP_ADDRESS or TA_IP6_ADDRESS"));
  704. Context->status = STATUS_INTERNAL_ERROR;
  705. Context->Completion((PSMB_ASYNC_CONTEXT)Context);
  706. return;
  707. }
  708. SendInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SendInfo[0]) + IpAddrSize, 'uBMS');
  709. if (NULL == SendInfo) {
  710. ExFreePool(pAddr);
  711. Context->status = STATUS_INSUFFICIENT_RESOURCES;
  712. Context->Completion((PSMB_ASYNC_CONTEXT)Context);
  713. return;
  714. }
  715. SendInfo->UserDataLength = 0;
  716. SendInfo->UserData = NULL;
  717. SendInfo->OptionsLength = 0;
  718. SendInfo->Options = NULL;
  719. SendInfo->RemoteAddressLength = IpAddrSize;
  720. SendInfo->RemoteAddress = (&SendInfo[1]);
  721. RtlCopyMemory(SendInfo->RemoteAddress, pAddr, IpAddrSize);
  722. ExFreePool(pAddr);
  723. pAddr = NULL;
  724. DeviceObject = IoGetRelatedDeviceObject(Context->TcpConnect.ConnectObject);
  725. Context->AsyncInternalContext = SendInfo;
  726. TdiBuildConnect(
  727. Irp,
  728. DeviceObject,
  729. Context->TcpConnect.ConnectObject,
  730. (PVOID)TdiConnectComplete,
  731. Context,
  732. NULL, // No timeout
  733. SendInfo,
  734. NULL
  735. );
  736. status = IoCallDriver(DeviceObject, Irp);
  737. SmbTrace (SMB_TRACE_CONNECT, ("pIrp %p return %!status!", Irp, status));
  738. }
  739. NTSTATUS
  740. SmbTcpDisconnect(
  741. PSMB_TCP_CONTEXT TcpContext,
  742. LONG TimeoutMilliseconds,
  743. ULONG Flags
  744. )
  745. {
  746. PIRP Irp = NULL;
  747. PFILE_OBJECT FileObject = NULL;
  748. PDEVICE_OBJECT DeviceObject = NULL;
  749. LARGE_INTEGER Timeout = { 0 };
  750. NTSTATUS status = STATUS_SUCCESS;
  751. FileObject = TcpContext->Connect.ConnectObject;
  752. if (NULL == FileObject) {
  753. ASSERT (0);
  754. SmbTrace(SMB_TRACE_CONNECT, ("NULL FileObject !!!!"));
  755. return STATUS_INVALID_PARAMETER;
  756. }
  757. DeviceObject = IoGetRelatedDeviceObject(FileObject);
  758. Irp = SmbAllocIrp(DeviceObject->StackSize);
  759. if (NULL == Irp) {
  760. SmbTrace(SMB_TRACE_CONNECT, ("no free IRP !!!!"));
  761. return STATUS_INSUFFICIENT_RESOURCES;
  762. }
  763. Timeout.QuadPart = -Int32x32To64(TimeoutMilliseconds, SMB_ONE_MILLISECOND);
  764. TdiBuildDisconnect(
  765. Irp,
  766. DeviceObject,
  767. FileObject,
  768. NULL,
  769. NULL,
  770. &Timeout,
  771. Flags,
  772. NULL,
  773. NULL
  774. );
  775. status = SubmitSynchTdiRequest(FileObject, Irp);
  776. SmbFreeIrp(Irp);
  777. SmbTrace (SMB_TRACE_CONNECT, ("return %!status!", status));
  778. return status;
  779. }