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.

637 lines
19 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. tdihndlr.c
  5. Abstract:
  6. TDI event handlers
  7. Author:
  8. Jiandong Ruan
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "ip2netbios.h"
  13. #include "tdihndlr.tmh"
  14. NTSTATUS
  15. TdiAcceptCompletion(
  16. IN PDEVICE_OBJECT DeviceObject,
  17. IN PIRP Irp,
  18. IN PSMB_TCP_CONNECT TcpConnect
  19. );
  20. void
  21. Inet_ntoa_nb(
  22. ULONG Address,
  23. PCHAR Buffer
  24. )
  25. /*++
  26. Routine Description: (Lifted from NBT4 tdihndlr.c)
  27. This routine converts an IP address into its "dotted quad" representation. The IP address is
  28. expected to be in network byte order. No attempt is made to handle the other dotted notions as
  29. defined in in.h. No error checking is done: all address values are permissible including 0
  30. and -1. The output string is blank padded to 16 characters to make the name look like a netbios
  31. name.
  32. The string representation is in ANSI, not UNICODE.
  33. The caller must allocate the storage, which should be 16 characters.
  34. Arguments:
  35. Address - IP address in network byte order
  36. Buffer - Pointer to buffer to receive string representation, ANSI
  37. Return Value:
  38. void
  39. --*/
  40. {
  41. ULONG i;
  42. UCHAR byte, c0, c1, c2;
  43. PCHAR p = Buffer;
  44. for (i = 0; i < 4; i++) {
  45. byte = (UCHAR) (Address & 0xff);
  46. c0 = byte % 10;
  47. byte /= 10;
  48. c1 = byte % 10;
  49. byte /= 10;
  50. c2 = byte;
  51. if (c2 != 0) {
  52. *p++ = c2 + '0';
  53. *p++ = c1 + '0';
  54. } else if (c1 != 0) {
  55. *p++ = c1 + '0';
  56. }
  57. *p++ = c0 + '0';
  58. if (i != 3)
  59. *p++ = '.';
  60. Address >>= 8;
  61. }
  62. // space pad up to 16 characters
  63. while (p < (Buffer + 16)) {
  64. *p++ = ' ';
  65. }
  66. }
  67. NTSTATUS
  68. SmbTdiConnectHandler(
  69. IN PSMB_DEVICE DeviceObject,
  70. IN LONG RemoteAddressLength,
  71. IN PTRANSPORT_ADDRESS RemoteAddress,
  72. IN LONG UserDataLength,
  73. IN PVOID UserData,
  74. IN LONG OptionsLength,
  75. IN PVOID Options,
  76. OUT CONNECTION_CONTEXT *ConnectionContext,
  77. OUT PIRP *AcceptIrp
  78. )
  79. /*++
  80. Routine Description:
  81. Arguments:
  82. Return Value:
  83. --*/
  84. {
  85. PSMB_CLIENT_ELEMENT SmbServer = NULL;
  86. KIRQL Irql;
  87. PTDI_IND_CONNECT evConnect = NULL;
  88. PVOID ConEvContext = NULL;
  89. NTSTATUS status = STATUS_SUCCESS, client_status = STATUS_SUCCESS;
  90. PVOID ClientConnectContext = NULL;
  91. PIRP ClientAcceptIrp = NULL;
  92. PIO_STACK_LOCATION IrpSp = NULL;
  93. PSMB_CONNECT ConnectObject = NULL;
  94. PSMB_CLIENT_ELEMENT ClientObject = NULL;
  95. PSMB_TCP_CONTEXT TcpContext = NULL;
  96. TA_NETBIOS_ADDRESS TaAddr;
  97. PTCPSEND_DISPATCH FastSend = NULL;
  98. BOOL NetbiosNameAllocated = FALSE;
  99. UNREFERENCED_PARAMETER(UserDataLength);
  100. UNREFERENCED_PARAMETER(UserData);
  101. UNREFERENCED_PARAMETER(OptionsLength);
  102. UNREFERENCED_PARAMETER(Options);
  103. //
  104. // Some smoke checks before acquiring the lock
  105. //
  106. if (SmbCfg.Unloading) {
  107. status = STATUS_DELETE_PENDING;
  108. goto error;
  109. }
  110. if (RemoteAddressLength < sizeof(TA_IP_ADDRESS) &&
  111. RemoteAddressLength < sizeof(TA_IP6_ADDRESS)) {
  112. status = STATUS_INVALID_ADDRESS;
  113. goto error;
  114. }
  115. if (RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP &&
  116. RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP6) {
  117. status = STATUS_INVALID_ADDRESS_COMPONENT;
  118. goto error;
  119. }
  120. //
  121. // Prevent SmbServer to go away by referencing the SmbServer
  122. //
  123. SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
  124. SmbServer = DeviceObject->SmbServer;
  125. if (NULL == SmbServer) {
  126. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  127. status = STATUS_REMOTE_NOT_LISTENING;
  128. goto error;
  129. }
  130. SmbReferenceClient(SmbServer, SMB_REF_CONNECT);
  131. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  132. if (SmbServer->PendingAcceptNumber > DeviceObject->MaxBackLog) {
  133. status = STATUS_NETWORK_BUSY;
  134. goto error;
  135. }
  136. SMB_ACQUIRE_SPINLOCK(SmbServer, Irql);
  137. if (!IsListEmpty(&SmbServer->ListenHead)) {
  138. ASSERTMSG ("TDI_LISTEN isn't supported", 0);
  139. SMB_RELEASE_SPINLOCK(SmbServer, Irql);
  140. status = STATUS_NOT_SUPPORTED;
  141. goto error;
  142. }
  143. evConnect = SmbServer->evConnect;
  144. ConEvContext = SmbServer->ConEvContext;
  145. SMB_RELEASE_SPINLOCK(SmbServer, Irql);
  146. SmbTrace(SMB_TRACE_CONNECT, ("Receive connect request"));
  147. //
  148. // No Listen
  149. //
  150. if (NULL == evConnect || NULL == ConEvContext) {
  151. status = STATUS_REMOTE_NOT_LISTENING;
  152. goto error;
  153. }
  154. //
  155. // Srv expects a TDI_ADDRESS_NETBIOS
  156. //
  157. TaAddr.TAAddressCount = 1;
  158. TaAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  159. TaAddr.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  160. TaAddr.Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  161. TcpContext = NULL;
  162. if (RemoteAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP) {
  163. FastSend = DeviceObject->Tcp4.FastSend;
  164. TcpContext = SmbAllocateInbound(&DeviceObject->Tcp4);
  165. Inet_ntoa_nb(((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].in_addr,
  166. TaAddr.Address[0].Address[0].NetbiosName);
  167. SmbPrint(SMB_TRACE_CONNECT, ("Connect request from %15.15s:%d\n",
  168. TaAddr.Address[0].Address[0].NetbiosName,
  169. htons(((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].sin_port)
  170. ));
  171. SmbTrace(SMB_TRACE_CONNECT, ("Connect request from %!ipaddr!:%!port!",
  172. ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].in_addr,
  173. ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].sin_port
  174. ));
  175. } else {
  176. SmbTrace(SMB_TRACE_CONNECT, ("Connect request from %!IPV6ADDR!:%!port!",
  177. (struct in6_addr*)&(((PTA_IP6_ADDRESS)RemoteAddress)->Address[0].Address[0].sin6_addr),
  178. ((PTA_IP6_ADDRESS)RemoteAddress)->Address[0].Address[0].sin6_port
  179. ));
  180. if (GetNetbiosNameFromIp6Address(((BYTE *)((PTA_IP6_ADDRESS)RemoteAddress)->Address[0].Address[0].sin6_addr),
  181. TaAddr.Address[0].Address[0].NetbiosName)) {
  182. NetbiosNameAllocated = TRUE;
  183. FastSend = DeviceObject->Tcp6.FastSend;
  184. TcpContext = SmbAllocateInbound(&DeviceObject->Tcp6);
  185. TODO("TdiConnectHandler: convert IP6 address into Netbios address");
  186. }
  187. }
  188. if (TcpContext == NULL) {
  189. status = STATUS_INSUFFICIENT_RESOURCES;
  190. goto error;
  191. }
  192. ClientConnectContext = NULL;
  193. ClientAcceptIrp = NULL;
  194. client_status = (*evConnect)(
  195. ConEvContext,
  196. sizeof(TaAddr),
  197. &TaAddr,
  198. 0,
  199. NULL,
  200. 0,
  201. NULL,
  202. &ClientConnectContext,
  203. &ClientAcceptIrp
  204. );
  205. SmbTrace(SMB_TRACE_CONNECT, ("evConnect: %!status! pIrp %p ClientContext %p",
  206. client_status, ClientAcceptIrp, ClientConnectContext));
  207. if (client_status != STATUS_MORE_PROCESSING_REQUIRED) {
  208. SmbFreeInbound(TcpContext);
  209. goto error;
  210. }
  211. ASSERT(ClientAcceptIrp);
  212. if (NULL == ClientAcceptIrp) {
  213. status = STATUS_INVALID_PARAMETER;
  214. goto error;
  215. }
  216. IrpSp = IoGetCurrentIrpStackLocation(ClientAcceptIrp);
  217. ConnectObject = IrpSp->FileObject->FsContext;
  218. if (IrpSp->FileObject->FsContext2 != UlongToPtr(SMB_TDI_CONNECT) ||
  219. ConnectObject->State != SMB_IDLE ||
  220. NULL != ConnectObject->TcpContext ||
  221. NULL == (ClientObject = ConnectObject->ClientObject)) {
  222. ClientAcceptIrp->IoStatus.Status = STATUS_INVALID_HANDLE;
  223. ClientAcceptIrp->IoStatus.Information = 0;
  224. IoCompleteRequest(ClientAcceptIrp, IO_NETWORK_INCREMENT);
  225. SmbFreeInbound(TcpContext);
  226. ASSERT (0);
  227. status = STATUS_INTERNAL_ERROR;
  228. goto error;
  229. }
  230. ConnectObject->Originator = FALSE;
  231. ConnectObject->FastSend = FastSend;
  232. SmbReuseConnectObject(ConnectObject);
  233. //
  234. // Reset the disconnection originator informaiton
  235. //
  236. ResetDisconnectOriginator(ConnectObject);
  237. ASSERT (TcpContext->Address.AddressHandle == NULL);
  238. ASSERT (TcpContext->Address.AddressObject == NULL);
  239. ASSERT (TcpContext->Connect.ConnectHandle);
  240. ASSERT (TcpContext->Connect.ConnectObject);
  241. SMB_ACQUIRE_SPINLOCK(DeviceObject, Irql);
  242. ASSERT(ClientObject == SmbServer);
  243. SMB_ACQUIRE_SPINLOCK_DPC(ClientObject);
  244. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  245. ASSERT(EntryIsInList(&ClientObject->AssociatedConnection, &ConnectObject->Linkage));
  246. ASSERT (ConnectObject->ClientContext == ClientConnectContext);
  247. //
  248. // Don't use SMB_CONNECTING because TCP4 could indicate the data before the AcceptCompletion
  249. // is called.
  250. //
  251. ConnectObject->State = SMB_CONNECTED;
  252. ConnectObject->TcpContext = TcpContext;
  253. TcpContext->Connect.pLastUprCnt = TcpContext->Connect.UpperConnect = ConnectObject;
  254. RtlCopyMemory(ConnectObject->RemoteName, TaAddr.Address[0].Address[0].NetbiosName, NETBIOS_NAME_SIZE);
  255. if (RemoteAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP) {
  256. ConnectObject->RemoteIpAddress.sin_family = SMB_AF_INET;
  257. ConnectObject->RemoteIpAddress.ip4.sin4_addr =
  258. ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].in_addr;
  259. } else {
  260. ConnectObject->RemoteIpAddress.sin_family = SMB_AF_INET6;
  261. RtlCopyMemory(ConnectObject->RemoteIpAddress.ip6.sin6_addr,
  262. ((PTA_IP6_ADDRESS)RemoteAddress)->Address[0].Address[0].sin6_addr,
  263. sizeof (ConnectObject->RemoteIpAddress.ip6.sin6_addr));
  264. ConnectObject->RemoteIpAddress.ip6.sin6_scope_id =
  265. ((PTA_IP6_ADDRESS)RemoteAddress)->Address[0].Address[0].sin6_scope_id;
  266. }
  267. //
  268. // Move the conection from AssociatedConnection list into PendingAcceptConnection
  269. //
  270. RemoveEntryList(&ConnectObject->Linkage);
  271. InsertTailList(&ClientObject->PendingAcceptConnection, &ConnectObject->Linkage);
  272. ClientObject->PendingAcceptNumber++;
  273. ASSERT(ClientObject->PendingAcceptNumber > 0);
  274. ConnectObject->PendingIRPs[SMB_PENDING_ACCEPT] = ClientAcceptIrp;
  275. SmbReferenceConnect(ConnectObject, SMB_REF_CONNECT);
  276. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  277. SMB_RELEASE_SPINLOCK_DPC(ClientObject);
  278. SMB_RELEASE_SPINLOCK(DeviceObject, Irql);
  279. TdiBuildAccept(
  280. ClientAcceptIrp,
  281. IoGetRelatedDeviceObject(TcpContext->Connect.ConnectObject),
  282. TcpContext->Connect.ConnectObject,
  283. TdiAcceptCompletion,
  284. &TcpContext->Connect,
  285. NULL,
  286. NULL
  287. );
  288. *ConnectionContext = &TcpContext->Connect;
  289. *AcceptIrp = ClientAcceptIrp;
  290. IoSetNextIrpStackLocation(ClientAcceptIrp);
  291. SmbDereferenceClient(SmbServer, SMB_REF_CONNECT);
  292. SmbTrace(SMB_TRACE_CONNECT, ("return STATUS_MORE_PROCESSING_REQUIRED to TCP/IP pIrp %p ClientContext %p",
  293. (*AcceptIrp), (*ConnectionContext)));
  294. return(STATUS_MORE_PROCESSING_REQUIRED);
  295. error:
  296. SmbTrace(SMB_TRACE_CONNECT, ("Refuse the connection: status=%!status! client status=%!status!",
  297. status, client_status));
  298. if (NetbiosNameAllocated) {
  299. FreeNetbiosNameForIp6Address(((BYTE *)((PTA_IP6_ADDRESS)RemoteAddress)->Address[0].Address[0].sin6_addr));
  300. }
  301. if (SmbServer) {
  302. SmbDereferenceClient(SmbServer, SMB_REF_CONNECT);
  303. }
  304. return STATUS_CONNECTION_REFUSED;
  305. }
  306. NTSTATUS
  307. TdiAcceptCompletion(
  308. IN PDEVICE_OBJECT DeviceObject,
  309. IN PIRP Irp,
  310. IN PSMB_TCP_CONNECT TcpConnect
  311. )
  312. {
  313. PSMB_CONNECT ConnectObject;
  314. PSMB_CLIENT_ELEMENT ClientObject;
  315. KIRQL Irql;
  316. PSMB_TCP_CONTEXT TcpContext;
  317. //
  318. // For performance consideration: check it before acquiring a lock:
  319. // This will allow SmbSynchAttackDetection and SmbSynchAttackCleanup
  320. // to run concurrently most of the time.
  321. //
  322. if (NULL == TcpConnect->UpperConnect) {
  323. goto cleanup2;
  324. }
  325. //
  326. // Grab the global lock to synchronize with the DoDisconnect
  327. //
  328. SMB_ACQUIRE_SPINLOCK (SmbCfg.SmbDeviceObject, Irql);
  329. ConnectObject = (PSMB_CONNECT)TcpConnect->UpperConnect;
  330. if (NULL == ConnectObject) {
  331. goto cleanup;
  332. }
  333. ClientObject = ConnectObject->ClientObject;
  334. ASSERT (NULL != ClientObject);
  335. ASSERT (NULL != ConnectObject->ClientObject);
  336. ASSERT (TcpConnect == &ConnectObject->TcpContext->Connect);
  337. SMB_ACQUIRE_SPINLOCK_DPC(ClientObject);
  338. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  339. ASSERT (ConnectObject->PendingIRPs[SMB_PENDING_ACCEPT] == Irp);
  340. ConnectObject->PendingIRPs[SMB_PENDING_ACCEPT] = NULL;
  341. ASSERT (EntryIsInList(&ClientObject->PendingAcceptConnection, &ConnectObject->Linkage));
  342. ASSERT (ClientObject->PendingAcceptNumber > 0);
  343. RemoveEntryList(&ConnectObject->Linkage);
  344. ClientObject->PendingAcceptNumber--;
  345. SmbTrace(SMB_TRACE_CONNECT, ("TDI_ACCEPT pIrp %p complete with %!status!",
  346. Irp, Irp->IoStatus.Status));
  347. //
  348. // The connection could have been disconnected when TCP completes the accepting IRP!!!
  349. // Only move it to active list if it hasn't been disconnected.
  350. //
  351. if (Irp->IoStatus.Status != STATUS_SUCCESS || ConnectObject->State != SMB_CONNECTED) {
  352. // BREAK_WHEN_TAKE();
  353. TcpContext = ConnectObject->TcpContext;
  354. ConnectObject->TcpContext = NULL;
  355. SmbDelayedDestroyTcpContext(TcpContext);
  356. InsertTailList(&ClientObject->AssociatedConnection, &ConnectObject->Linkage);
  357. ConnectObject->State = SMB_IDLE;
  358. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  359. Irp->IoStatus.Status = STATUS_CONNECTION_RESET;
  360. }
  361. if (ConnectObject->RemoteIpAddress.sin_family == SMB_AF_INET6) {
  362. FreeNetbiosNameForIp6Address(ConnectObject->RemoteIpAddress.ip6.sin6_addr_bytes);
  363. ConnectObject->RemoteIpAddress.sin_family = SMB_AF_INVALID_INET6;
  364. }
  365. } else {
  366. InsertTailList(&ClientObject->ActiveConnection, &ConnectObject->Linkage);
  367. }
  368. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  369. SMB_RELEASE_SPINLOCK_DPC(ClientObject);
  370. cleanup:
  371. SMB_RELEASE_SPINLOCK(SmbCfg.SmbDeviceObject, Irql);
  372. if (ConnectObject) {
  373. SmbDereferenceConnect(ConnectObject, SMB_REF_CONNECT);
  374. }
  375. cleanup2:
  376. return STATUS_SUCCESS;
  377. }
  378. NTSTATUS
  379. TdiSetEventHandler(
  380. PFILE_OBJECT FileObject,
  381. ULONG EventType,
  382. PVOID EventHandler,
  383. PVOID Context
  384. )
  385. {
  386. PIRP Irp;
  387. KEVENT Event;
  388. NTSTATUS status;
  389. PDEVICE_OBJECT DeviceObject;
  390. PAGED_CODE();
  391. DeviceObject = IoGetRelatedDeviceObject(FileObject);
  392. Irp = SmbAllocIrp(DeviceObject->StackSize);
  393. if (Irp == NULL) {
  394. return STATUS_INSUFFICIENT_RESOURCES;
  395. }
  396. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  397. TdiBuildSetEventHandler(
  398. Irp,
  399. DeviceObject,
  400. FileObject,
  401. SmbSynchTdiCompletion,
  402. &Event,
  403. EventType,
  404. EventHandler,
  405. Context
  406. );
  407. status = IoCallDriver(DeviceObject, Irp);
  408. if (!NT_SUCCESS(status)) {
  409. SmbFreeIrp(Irp);
  410. return status;
  411. }
  412. if (status == STATUS_PENDING) {
  413. status = KeWaitForSingleObject(
  414. &Event,
  415. Executive,
  416. KernelMode,
  417. FALSE,
  418. NULL
  419. );
  420. ASSERT(status == STATUS_WAIT_0);
  421. status = Irp->IoStatus.Status;
  422. }
  423. SmbFreeIrp(Irp);
  424. return status;
  425. }
  426. NTSTATUS
  427. SmbTdiDisconnectHandler (
  428. IN PSMB_DEVICE DeviceObject,
  429. IN PSMB_TCP_CONNECT TcpConnect,
  430. IN LONG DisconnectDataLength,
  431. IN PVOID DisconnectData,
  432. IN LONG DisconnectInformationLength,
  433. IN PVOID DisconnectInformation,
  434. IN ULONG DisconnectFlags
  435. )
  436. {
  437. KIRQL Irql;
  438. NTSTATUS status;
  439. PSMB_CONNECT ConnectObject;
  440. //
  441. // Reference the connection object make sure it won't go away
  442. //
  443. SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
  444. ConnectObject = (PSMB_CONNECT)TcpConnect->UpperConnect;
  445. if (NULL == ConnectObject) {
  446. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  447. return STATUS_SUCCESS;
  448. }
  449. SmbReferenceConnect(ConnectObject, SMB_REF_DISCONNECT);
  450. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  451. SmbTrace (SMB_TRACE_CONNECT, ("TCP Disconnect Indication: ConnOb %p Flag %d",
  452. ConnectObject, DisconnectFlags));
  453. status = CommonDisconnectHandler(DeviceObject, ConnectObject, DisconnectFlags);
  454. SmbDereferenceConnect(ConnectObject, SMB_REF_DISCONNECT);
  455. return status;
  456. }
  457. NTSTATUS
  458. CommonDisconnectHandler (
  459. IN PSMB_DEVICE DeviceObject,
  460. IN PSMB_CONNECT ConnectObject,
  461. IN ULONG DisconnectFlags
  462. )
  463. {
  464. PSMB_CLIENT_ELEMENT ClientObject;
  465. KIRQL Irql;
  466. PTDI_IND_DISCONNECT evDisConnect;
  467. PVOID DiscEvContext;
  468. PVOID ClientContext;
  469. PSMB_TCP_CONTEXT TcpContext;
  470. NTSTATUS status;
  471. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  472. ClientObject = ConnectObject->ClientObject;
  473. if (NULL == ClientObject) {
  474. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  475. return STATUS_SUCCESS;
  476. }
  477. SmbTrace(SMB_TRACE_CONNECT, ("receive disconnection indication for %p", ConnectObject));
  478. TcpContext = ConnectObject->TcpContext;
  479. ConnectObject->TcpContext = NULL;
  480. if (NULL == TcpContext) {
  481. ASSERT(ConnectObject->State == SMB_IDLE);
  482. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  483. return STATUS_SUCCESS;
  484. }
  485. ASSERT(ConnectObject->State == SMB_CONNECTED || ConnectObject->State == SMB_CONNECTING);
  486. ConnectObject->State = SMB_IDLE;
  487. SaveDisconnectOriginator(ConnectObject, SMB_DISCONNECT_FROM_TRANSPORT);
  488. evDisConnect = ClientObject->evDisconnect;
  489. DiscEvContext = ClientObject->DiscEvContext;
  490. ClientContext = ConnectObject->ClientContext;
  491. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  492. //
  493. // Cleanup the endpoint so that the client can reuse it
  494. //
  495. // Don't wait for the tcp-layer disconnect completion since
  496. // the disconnection isn't generated by our clients.
  497. //
  498. SmbDisconnectCleanup(DeviceObject, ClientObject, ConnectObject,
  499. TcpContext, TDI_DISCONNECT_ABORT, FALSE);
  500. //
  501. // Notify our client
  502. //
  503. if (evDisConnect) {
  504. status = (*evDisConnect)(
  505. DiscEvContext,
  506. ClientContext,
  507. 0,
  508. NULL,
  509. 0,
  510. NULL,
  511. DisconnectFlags
  512. );
  513. SmbTrace(SMB_TRACE_CONNECT, ("client returns %!status! for disconnect event", status));
  514. }
  515. return STATUS_SUCCESS;
  516. }