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.

1253 lines
38 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. connect.c
  5. Abstract:
  6. Implement the session setup/shutdown (TDI_CONNECT and TDI_DISCONNECT)
  7. Author:
  8. Jiandong Ruan
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "connect.tmh"
  13. NTSTATUS
  14. FindTdiAddress(
  15. PVOID TdiAddress,
  16. ULONG TdiAddressLength,
  17. USHORT AddressType,
  18. PVOID *AddressFound,
  19. PULONG AddressLength
  20. );
  21. void
  22. SmbGetHostCompletion(
  23. PSMB_GETHOST_CONTEXT Context
  24. );
  25. VOID
  26. SmbStartTcpSession (
  27. PSMB_CONNECT_CONTEXT pSmbConnectContext
  28. );
  29. void
  30. SmbStartTcpSessionCompletion(
  31. PSMB_CONNECT_CONTEXT Context
  32. );
  33. NTSTATUS
  34. SmbQueueStartTcpSession (
  35. IN PSMB_CONNECT_CONTEXT pSmbConnectContext
  36. );
  37. NTSTATUS
  38. SmbCheckConnect(
  39. PSMB_CONNECT ConnectObject
  40. )
  41. /*++
  42. Routine Description:
  43. This function checks if a connection object is in a valid state
  44. for making a connection.
  45. Arguments:
  46. Return Value:
  47. --*/
  48. {
  49. ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
  50. if (IsDisAssociated(ConnectObject)) {
  51. ASSERT(0);
  52. return STATUS_INVALID_HANDLE;
  53. }
  54. if (IsBusy(ConnectObject)) {
  55. return STATUS_DEVICE_BUSY;
  56. }
  57. if (!IsDisconnected(ConnectObject)) {
  58. return STATUS_INVALID_DEVICE_REQUEST;
  59. }
  60. //
  61. // Don't allow SRV to make outbound connection
  62. //
  63. if (ConnectObject->ClientObject == ConnectObject->Device->SmbServer) {
  64. ASSERT(0);
  65. return STATUS_INVALID_DEVICE_REQUEST;
  66. }
  67. if (ConnectObject->TcpContext) {
  68. ASSERT(0);
  69. return STATUS_INVALID_DEVICE_REQUEST;
  70. }
  71. return STATUS_SUCCESS;
  72. }
  73. NTSTATUS
  74. SmbConnect(
  75. PSMB_DEVICE Device,
  76. PIRP Irp
  77. )
  78. /*++
  79. Routine Description:
  80. TDI_CONNECT
  81. Note:
  82. Starting from Whistler, RDR always send us a TDI_NETBIOS_UNICODE_EX address. Support for
  83. other address type is postponed. TDI_NETBIOS_UNICODE_EX is a superset of TDI_NETBIOS and
  84. TDI_NETBIOS_EX.
  85. Arguments:
  86. Return Value:
  87. Note:
  88. Since it is inconvinient to clean up TCP connection (it requires PASSIVE_LEVEL),
  89. we don't cleanup it. We still keep the TCP connection even though we got an error.
  90. The cleanup of TCP connections will be postponed until the client call TDI_DISCONNECT,
  91. TDI_DISASSOCIATE_ADDRESS or close the connection.
  92. --*/
  93. {
  94. DWORD Size = 0;
  95. PSMB_GETHOST_CONTEXT Context = NULL;
  96. PIO_STACK_LOCATION IrpSp = NULL;
  97. KIRQL Irql;
  98. PSMB_CONNECT ConnectObject = NULL;
  99. NTSTATUS status;
  100. ULONG AddressLength;
  101. PTDI_REQUEST_KERNEL pRequestKernel = NULL;
  102. UNICODE_STRING RemoteName;
  103. PTDI_ADDRESS_NETBIOS_UNICODE_EX pUnicodeAddress = NULL;
  104. PAGED_CODE();
  105. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  106. ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_CONNECT);
  107. if (NULL == ConnectObject) {
  108. ASSERT(0);
  109. return STATUS_INVALID_HANDLE;
  110. }
  111. pRequestKernel = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
  112. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: pIrp %p ConnectOb %p", Irp, ConnectObject));
  113. SmbPrint (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p\n", ConnectObject));
  114. //
  115. // Mark ConnectObject pending
  116. //
  117. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  118. status = SmbCheckConnect(ConnectObject);
  119. if (STATUS_SUCCESS != status) {
  120. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  121. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  122. ASSERT(status != STATUS_PENDING);
  123. SmbDereferenceConnect(ConnectObject, SMB_REF_CONNECT);
  124. return status;
  125. }
  126. IoMarkIrpPending(Irp);
  127. SmbReuseConnectObject(ConnectObject);
  128. ConnectObject->State = SMB_CONNECTING;
  129. ConnectObject->PendingIRPs[SMB_PENDING_CONNECT] = Irp;
  130. ConnectObject->Originator = TRUE;
  131. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  132. //
  133. // Get remote name
  134. //
  135. status = FindTdiAddress(
  136. pRequestKernel->RequestConnectionInformation->RemoteAddress,
  137. pRequestKernel->RequestConnectionInformation->RemoteAddressLength,
  138. TDI_ADDRESS_TYPE_NETBIOS_UNICODE_EX,
  139. &pUnicodeAddress,
  140. &AddressLength
  141. );
  142. if (status != STATUS_SUCCESS || AddressLength < sizeof(TDI_ADDRESS_NETBIOS_UNICODE_EX)) {
  143. status = STATUS_INVALID_ADDRESS_COMPONENT;
  144. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  145. goto cleanup;
  146. }
  147. //
  148. // We support only NBT_READWRITE buffer type
  149. //
  150. if (pUnicodeAddress->NameBufferType != NBT_READWRITE) {
  151. status = STATUS_INVALID_ADDRESS_COMPONENT;
  152. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  153. goto cleanup;
  154. }
  155. if (pUnicodeAddress->RemoteName.Buffer != pUnicodeAddress->RemoteNameBuffer) {
  156. status = STATUS_INVALID_ADDRESS_COMPONENT;
  157. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  158. goto cleanup;
  159. }
  160. if (pUnicodeAddress->RemoteName.MaximumLength < sizeof(WCHAR)) {
  161. ASSERT(0);
  162. status = STATUS_INVALID_ADDRESS_COMPONENT;
  163. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  164. goto cleanup;
  165. }
  166. if (AddressLength < pUnicodeAddress->RemoteName.MaximumLength + sizeof(TDI_ADDRESS_NETBIOS_UNICODE_EX) - 2) {
  167. ASSERT(0);
  168. status = STATUS_INVALID_ADDRESS_COMPONENT;
  169. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  170. goto cleanup;
  171. }
  172. //
  173. // Do DNS name resolution
  174. //
  175. Size = ALIGN(sizeof(SMB_GETHOST_CONTEXT)) + DNS_NAME_BUFFER_LENGTH * sizeof(WCHAR);
  176. Context = (PSMB_GETHOST_CONTEXT)ExAllocatePoolWithTag(
  177. NonPagedPool,
  178. Size,
  179. 'hBMS'
  180. );
  181. if (NULL == Context) {
  182. status = STATUS_NO_MEMORY;
  183. SmbTrace (SMB_TRACE_CONNECT, ("TDI_CONNECT: %p %!status!", ConnectObject, status));
  184. goto cleanup;
  185. }
  186. SmbInitAsyncContext(
  187. (PSMB_ASYNC_CONTEXT)Context,
  188. (PSMB_TDI_COMPLETION)SmbGetHostCompletion,
  189. ConnectObject,
  190. SmbCfg.DnsTimeout
  191. );
  192. Context->pUnicodeAddress = pUnicodeAddress;
  193. Context->FQDN.Buffer = (WCHAR*)(((PUCHAR)Context) + ALIGN(sizeof(SMB_GETHOST_CONTEXT)));
  194. Context->FQDN.Length = 0;
  195. Context->FQDN.MaximumLength = DNS_NAME_BUFFER_LENGTH * sizeof(WCHAR);
  196. RemoteName = pUnicodeAddress->RemoteName;
  197. SmbTrace (SMB_TRACE_CONNECT, ("%p: Resolving %Z", ConnectObject, &RemoteName));
  198. SmbPrint (SMB_TRACE_CONNECT, ("%p: Resolving %Z\n", ConnectObject, &RemoteName));
  199. SmbAsyncGetHostByName(&RemoteName, Context);
  200. return STATUS_PENDING;
  201. cleanup:
  202. ASSERT (NULL == Context);
  203. SmbSessionCompleteRequest(
  204. ConnectObject,
  205. STATUS_BAD_NETWORK_PATH,
  206. 0
  207. );
  208. return STATUS_PENDING;
  209. }
  210. BOOL
  211. IsSmbBoundToOutgoingInterface4(
  212. ULONG DestIp
  213. )
  214. {
  215. NTSTATUS status;
  216. ULONG Metric, OutgoingIfIndex;
  217. KIRQL Irql;
  218. PIP4FASTQUERY FastQuery = NULL;
  219. PLIST_ENTRY entry = NULL;
  220. PSMB_TCP_DEVICE pIf = NULL;
  221. BOOL found = FALSE;
  222. FastQuery = SmbCfg.SmbDeviceObject->Tcp4.FastQuery;
  223. if (NULL == FastQuery) {
  224. return TRUE;
  225. }
  226. if (INVALID_INTERFACE_INDEX == SmbCfg.SmbDeviceObject->Tcp4.LoopbackInterfaceIndex) {
  227. status = ((PIP4FASTQUERY)(FastQuery))(ntohl(INADDR_LOOPBACK), &OutgoingIfIndex, &Metric);
  228. if (status == STATUS_SUCCESS) {
  229. SmbCfg.SmbDeviceObject->Tcp4.LoopbackInterfaceIndex = OutgoingIfIndex;
  230. SmbPrint(SMB_TRACE_TCP, ("Loopback Interface Index = %d\n", OutgoingIfIndex));
  231. SmbTrace(SMB_TRACE_TCP, ("Loopback Interface Index = %d", OutgoingIfIndex));
  232. } else {
  233. SmbPrint(SMB_TRACE_TCP, ("Query loopback Interface Index returns 0x%08lx\n", status));
  234. SmbTrace(SMB_TRACE_TCP, ("Query loopback Interface Index returns %!status!", status));
  235. SmbCfg.SmbDeviceObject->Tcp4.LoopbackInterfaceIndex = INVALID_INTERFACE_INDEX;
  236. }
  237. }
  238. status = (FastQuery)(DestIp, &OutgoingIfIndex, &Metric);
  239. if (STATUS_SUCCESS != status || OutgoingIfIndex == INVALID_INTERFACE_INDEX) {
  240. //
  241. // TCP cannot find a route, return TRUE anyway
  242. //
  243. return TRUE;
  244. }
  245. if (OutgoingIfIndex == SmbCfg.SmbDeviceObject->Tcp4.LoopbackInterfaceIndex) {
  246. //
  247. // This is a local address
  248. //
  249. return TRUE;
  250. }
  251. //
  252. // This is a remote address
  253. //
  254. found = FALSE;
  255. SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
  256. entry = SmbCfg.IPDeviceList.Flink;
  257. while(entry != &SmbCfg.IPDeviceList) {
  258. pIf = CONTAINING_RECORD(entry, SMB_TCP_DEVICE, Linkage);
  259. entry = entry->Flink;
  260. if (pIf->InterfaceIndex != OutgoingIfIndex) {
  261. continue;
  262. }
  263. if (pIf->PrimaryIpAddress.sin_family == SMB_AF_INET && pIf->PrimaryIpAddress.ip4.sin4_addr) {
  264. found = pIf->EnableOutbound;
  265. break;
  266. }
  267. }
  268. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  269. return found;
  270. }
  271. VOID
  272. SmbCompleteConnectAttempts (
  273. PSMB_CONNECT_CONTEXT pSmbConnectContext
  274. )
  275. /*++
  276. Routine Description:
  277. Complete the connect attempts
  278. Arguments:
  279. Return Value:
  280. --*/
  281. {
  282. PSMB_GETHOST_CONTEXT pSmbGetHostContext = pSmbConnectContext->pSmbGetHostContext;
  283. PSMB_CONNECT ConnectObject = (PSMB_CONNECT)pSmbGetHostContext->ClientContext;
  284. NTSTATUS status = pSmbConnectContext->status;
  285. //
  286. // Set the proper status
  287. //
  288. if (pSmbConnectContext->usCurrentIP >= pSmbGetHostContext->ipaddr_num &&
  289. STATUS_INSUFFICIENT_RESOURCES != status) {
  290. status = STATUS_BAD_NETWORK_PATH;
  291. }
  292. SmbSessionCompleteRequest(ConnectObject, status, 0);
  293. ExFreePool(pSmbGetHostContext);
  294. ExFreePool(pSmbConnectContext);
  295. }
  296. VOID
  297. SmbDelayedStartTcpSession (
  298. IN PDEVICE_OBJECT pDeviceObject,
  299. IN PVOID pContext
  300. )
  301. {
  302. PSMB_CONNECT_CONTEXT pSmbConnectContext = pContext;
  303. PAGED_CODE();
  304. IoFreeWorkItem (pSmbConnectContext->pIoWorkItem);
  305. pSmbConnectContext->pIoWorkItem = NULL;
  306. SmbStartTcpSession (pSmbConnectContext);
  307. }
  308. void
  309. SmbStartTcpSessionCompletion(
  310. PSMB_CONNECT_CONTEXT pSmbConnectContext
  311. )
  312. /*++
  313. Routine Description:
  314. This routine will be called after TCP level session setup is finished.
  315. Arguments:
  316. Return Value:
  317. --*/
  318. {
  319. PSMB_GETHOST_CONTEXT pSmbGetHostContext = pSmbConnectContext->pSmbGetHostContext;
  320. PSMB_CONNECT ConnectObject = (PSMB_CONNECT)pSmbConnectContext->ClientContext;
  321. KIRQL Irql = 0;
  322. PSMB_TCP_CONTEXT pTcpContext = NULL;
  323. NTSTATUS status = STATUS_SUCCESS;
  324. SmbTrace (SMB_TRACE_CONNECT, ("TcpSession Complete: %p %!status!", ConnectObject, pSmbConnectContext->status));
  325. SmbPrint (SMB_TRACE_CONNECT, ("TcpSession Complete: %p %08lx\n", ConnectObject, pSmbConnectContext->status));
  326. switch (pSmbConnectContext->status) {
  327. case STATUS_SUCCESS:
  328. case STATUS_INSUFFICIENT_RESOURCES:
  329. case STATUS_CANCELLED:
  330. goto done;
  331. }
  332. //
  333. // Advance to the next IP address
  334. //
  335. pSmbConnectContext->usCurrentIP++;
  336. if (pSmbConnectContext->usCurrentIP >= pSmbGetHostContext->ipaddr_num) {
  337. goto done;
  338. }
  339. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  340. pTcpContext = ConnectObject->TcpContext;
  341. ConnectObject->TcpContext = NULL;
  342. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  343. SmbDelayedDestroyTcpContext (pTcpContext);
  344. status = SmbQueueStartTcpSession(pSmbConnectContext);
  345. if (STATUS_SUCCESS != status) {
  346. pSmbConnectContext->status = status;
  347. goto done;
  348. }
  349. return;
  350. done:
  351. SmbCompleteConnectAttempts (pSmbConnectContext);
  352. }
  353. NTSTATUS
  354. SmbQueueStartTcpSession (
  355. IN PSMB_CONNECT_CONTEXT pSmbConnectContext
  356. )
  357. {
  358. PIO_WORKITEM pIoWorkItem = NULL;
  359. NTSTATUS status = STATUS_SUCCESS;
  360. pIoWorkItem = IoAllocateWorkItem ((PDEVICE_OBJECT)SmbCfg.SmbDeviceObject);
  361. if (NULL == pIoWorkItem) {
  362. status = STATUS_INSUFFICIENT_RESOURCES;
  363. goto done;
  364. }
  365. pSmbConnectContext->pIoWorkItem = pIoWorkItem;
  366. IoQueueWorkItem (
  367. pIoWorkItem,
  368. SmbDelayedStartTcpSession,
  369. DelayedWorkQueue,
  370. pSmbConnectContext
  371. );
  372. done:
  373. return status;
  374. }
  375. VOID
  376. SmbStartTcpSession (
  377. PSMB_CONNECT_CONTEXT pSmbConnectContext
  378. )
  379. {
  380. PSMB_GETHOST_CONTEXT pSmbGetHostContext = pSmbConnectContext->pSmbGetHostContext;
  381. PSMB_CONNECT ConnectObject = (PSMB_CONNECT)pSmbGetHostContext->ClientContext;
  382. NTSTATUS status = STATUS_SUCCESS;
  383. PSMB_TCP_CONTEXT TcpContext = NULL;
  384. USHORT Port;
  385. PSMB_IP_ADDRESS pSmbIpAddress = NULL;
  386. BOOLEAN bTryAllocateResource = FALSE;
  387. KIRQL Irql = 0;
  388. ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
  389. ASSERT (ConnectObject->TcpContext == NULL);
  390. for (
  391. TcpContext = NULL, bTryAllocateResource = FALSE;
  392. pSmbConnectContext->usCurrentIP < pSmbGetHostContext->ipaddr_num;
  393. pSmbConnectContext->usCurrentIP++
  394. ) {
  395. pSmbIpAddress = &pSmbGetHostContext->ipaddr[pSmbConnectContext->usCurrentIP];
  396. switch (pSmbIpAddress->sin_family) {
  397. case SMB_AF_INET:
  398. if (SmbCfg.Tcp4Available &&
  399. IsSmbBoundToOutgoingInterface4(pSmbIpAddress->ip4.sin4_addr)) {
  400. TcpContext = SmbAllocateOutbound(&ConnectObject->Device->Tcp4);
  401. Port = ConnectObject->Device->Tcp4.Port;
  402. ConnectObject->FastSend = ConnectObject->Device->Tcp4.FastSend;
  403. bTryAllocateResource = TRUE;
  404. SmbTrace (SMB_TRACE_CONNECT, ("%p: try %d-th IP address: %!ipaddr!",
  405. ConnectObject,
  406. pSmbConnectContext->usCurrentIP + 1,
  407. pSmbIpAddress->ip4.sin4_addr));
  408. SmbPrint (SMB_TRACE_CONNECT, ("%p: try %d-th IP address: IPv4\n",
  409. ConnectObject,
  410. pSmbConnectContext->usCurrentIP + 1));
  411. } else {
  412. SmbTrace (SMB_TRACE_CONNECT, ("%p: skip %d-th IP address: %!ipaddr!",
  413. ConnectObject,
  414. pSmbConnectContext->usCurrentIP + 1,
  415. pSmbIpAddress->ip4.sin4_addr));
  416. SmbPrint (SMB_TRACE_CONNECT, ("%p: skip %d-th IP address: IPv4\n",
  417. ConnectObject,
  418. pSmbConnectContext->usCurrentIP + 1));
  419. }
  420. break;
  421. case SMB_AF_INET6:
  422. if (SmbCfg.Tcp6Available &&
  423. (SmbCfg.bIPv6EnableOutboundGlobal ||
  424. SMB_IS_ADDRESS_ALLOWED(pSmbIpAddress->ip6.sin6_addr_bytes))) {
  425. TcpContext = SmbAllocateOutbound(&ConnectObject->Device->Tcp6);
  426. Port = ConnectObject->Device->Tcp6.Port;
  427. ConnectObject->FastSend = ConnectObject->Device->Tcp6.FastSend;
  428. bTryAllocateResource = TRUE;
  429. SmbTrace (SMB_TRACE_CONNECT, ("%p: try %d-th IP address: %!IPV6ADDR!",
  430. ConnectObject,
  431. pSmbConnectContext->usCurrentIP + 1,
  432. (PVOID)pSmbIpAddress->ip6.sin6_addr
  433. ));
  434. } else {
  435. SmbTrace (SMB_TRACE_CONNECT, ("%p: skip %d-th IP address: %!IPV6ADDR!",
  436. ConnectObject,
  437. pSmbConnectContext->usCurrentIP + 1,
  438. (PVOID)pSmbIpAddress->ip6.sin6_addr
  439. ));
  440. }
  441. break;
  442. default:
  443. ASSERT (0);
  444. break;
  445. }
  446. if (NULL != TcpContext) {
  447. break;
  448. }
  449. }
  450. if (NULL == TcpContext) {
  451. status = (bTryAllocateResource)? STATUS_INSUFFICIENT_RESOURCES: STATUS_BAD_NETWORK_PATH;
  452. goto cleanup;
  453. }
  454. ASSERT (pSmbConnectContext->usCurrentIP < pSmbGetHostContext->ipaddr_num);
  455. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  456. ConnectObject->TcpContext = TcpContext;
  457. ConnectObject->StateRcvHandler = WaitingHeader;
  458. ConnectObject->HeaderBytesRcved = 0;
  459. TcpContext->Connect.pLastUprCnt = TcpContext->Connect.UpperConnect = ConnectObject;
  460. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  461. //
  462. // TBD: SmbAsyncConnect should honor the timeout
  463. //
  464. SmbInitAsyncContext(
  465. (PSMB_ASYNC_CONTEXT)pSmbConnectContext,
  466. (PSMB_TDI_COMPLETION)SmbStartTcpSessionCompletion,
  467. ConnectObject,
  468. 5000 // 5 seconds timeout. It is not honored by SmbAysncConnect
  469. );
  470. ConnectObject->RemoteIpAddress = pSmbIpAddress[0];
  471. pSmbConnectContext->TcpConnect = TcpContext->Connect;
  472. SmbAsyncConnect(
  473. pSmbIpAddress,
  474. Port,
  475. pSmbConnectContext
  476. );
  477. return;
  478. cleanup:
  479. ASSERT (pSmbConnectContext->usCurrentIP >= pSmbGetHostContext->ipaddr_num);
  480. ASSERT (status != STATUS_SUCCESS);
  481. pSmbConnectContext->status = status;
  482. SmbCompleteConnectAttempts (pSmbConnectContext);
  483. }
  484. void
  485. SmbGetHostCompletion(
  486. PSMB_GETHOST_CONTEXT Context
  487. )
  488. /*++
  489. Routine Description:
  490. This routine will be called after we get a result for dns name resolution
  491. Arguments:
  492. Return Value:
  493. --*/
  494. {
  495. PSMB_CONNECT ConnectObject = (PSMB_CONNECT)Context->ClientContext;
  496. NTSTATUS status = Context->status;
  497. PSMB_CONNECT_CONTEXT pSmbConnectContext = NULL;
  498. ASSERT(NULL != ConnectObject);
  499. SmbTrace (SMB_TRACE_CONNECT, ("%p: name resolution completed with %!status!", ConnectObject, status));
  500. SmbPrint (SMB_TRACE_CONNECT, ("%p: name resolution completed with %08lx\n", ConnectObject, status));
  501. if (STATUS_SUCCESS != status) {
  502. if (status != STATUS_CANCELLED) {
  503. status = STATUS_BAD_NETWORK_PATH;
  504. }
  505. goto cleanup;
  506. }
  507. pSmbConnectContext = (PSMB_CONNECT_CONTEXT)ExAllocatePoolWithTag(
  508. NonPagedPool,
  509. sizeof(SMB_CONNECT_CONTEXT),
  510. 'sBMS'
  511. );
  512. if (NULL == pSmbConnectContext) {
  513. status = STATUS_INSUFFICIENT_RESOURCES;
  514. goto cleanup;
  515. }
  516. RtlZeroMemory (pSmbConnectContext, sizeof(SMB_CONNECT_CONTEXT));
  517. pSmbConnectContext->ClientContext = ConnectObject;
  518. pSmbConnectContext->usCurrentIP = 0;
  519. pSmbConnectContext->pSmbGetHostContext = Context;
  520. pSmbConnectContext->pIoWorkItem = NULL;
  521. SmbTrace (SMB_TRACE_CONNECT, ("%p: find %d IP address", ConnectObject, Context->ipaddr_num));
  522. SmbPrint (SMB_TRACE_CONNECT, ("%p: find %d IP address\n", ConnectObject, Context->ipaddr_num));
  523. status = SmbQueueStartTcpSession(pSmbConnectContext);
  524. if (STATUS_SUCCESS != status) {
  525. goto cleanup;
  526. }
  527. return;
  528. cleanup:
  529. if (NULL != Context) {
  530. ExFreePool(Context);
  531. }
  532. if (NULL != pSmbConnectContext) {
  533. ExFreePool(pSmbConnectContext);
  534. }
  535. SmbSessionCompleteRequest(ConnectObject, status, 0);
  536. }
  537. NTSTATUS
  538. DisconnDone(
  539. IN PDEVICE_OBJECT DeviceObject,
  540. IN PIRP Irp,
  541. IN PSMB_TCP_CONTEXT TcpContext
  542. )
  543. {
  544. KIRQL Irql;
  545. PSMB_DEVICE SmbDevice;
  546. SmbDevice = SmbCfg.SmbDeviceObject;
  547. ASSERT(TcpContext->DisconnectIrp == Irp);
  548. SMB_ACQUIRE_SPINLOCK(SmbDevice, Irql);
  549. ASSERT(EntryIsInList(&SmbDevice->PendingDisconnectList, &TcpContext->Linkage));
  550. RemoveEntryList(&TcpContext->Linkage);
  551. InitializeListHead(&TcpContext->Linkage);
  552. SmbDevice->PendingDisconnectListNumber--;
  553. ASSERT(SmbDevice->PendingDisconnectListNumber >= 0);
  554. TcpContext->DisconnectIrp = NULL;
  555. if (IsListEmpty(&SmbDevice->PendingDisconnectList)) {
  556. KeSetEvent(&SmbDevice->PendingDisconnectListEmptyEvent, 0, FALSE);
  557. ASSERT(SmbDevice->PendingDisconnectListNumber == 0);
  558. }
  559. SMB_RELEASE_SPINLOCK(SmbDevice, Irql);
  560. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  561. SmbFreeTcpContext(TcpContext);
  562. } else {
  563. SmbDelayedDestroyTcpContext(TcpContext);
  564. }
  565. SmbFreeIrp(Irp);
  566. return STATUS_MORE_PROCESSING_REQUIRED;
  567. }
  568. NTSTATUS
  569. SmbAsynchTcpDisconnect(
  570. PSMB_TCP_CONTEXT TcpContext,
  571. ULONG Flags
  572. )
  573. {
  574. PIRP Irp;
  575. PFILE_OBJECT FileObject;
  576. PDEVICE_OBJECT DeviceObject;
  577. NTSTATUS status;
  578. FileObject = TcpContext->Connect.ConnectObject;
  579. if (NULL == FileObject) {
  580. ASSERT (0);
  581. SmbTrace(SMB_TRACE_TCP, ("NULL FileObject !!!!"));
  582. return STATUS_INVALID_PARAMETER;
  583. }
  584. DeviceObject = IoGetRelatedDeviceObject(FileObject);
  585. Irp = SmbAllocIrp(DeviceObject->StackSize);
  586. if (NULL == Irp) {
  587. SmbTrace(SMB_TRACE_TCP, ("no free IRP !!!!"));
  588. return STATUS_INSUFFICIENT_RESOURCES;
  589. }
  590. TcpContext->DisconnectIrp = Irp;
  591. TdiBuildDisconnect(
  592. Irp,
  593. DeviceObject,
  594. FileObject,
  595. (PIO_COMPLETION_ROUTINE)DisconnDone,
  596. TcpContext,
  597. NULL,
  598. Flags,
  599. NULL,
  600. NULL
  601. );
  602. status = IoCallDriver(DeviceObject, Irp);
  603. SmbTrace (SMB_TRACE_CONNECT, ("return %!status!", status));
  604. return STATUS_PENDING;
  605. }
  606. VOID
  607. SmbDelayedDisconnectTcp(
  608. IN PSMB_DEVICE DeviceObject,
  609. IN PIO_WORKITEM WorkItem
  610. )
  611. {
  612. KIRQL Irql;
  613. PLIST_ENTRY entry;
  614. NTSTATUS status;
  615. ULONG DisconnectFlag;
  616. PSMB_TCP_CONTEXT TcpContext;
  617. PAGED_CODE();
  618. ASSERT (DeviceObject->DisconnectWorkerRunning == TRUE);
  619. while(1) {
  620. SMB_ACQUIRE_SPINLOCK(DeviceObject, Irql);
  621. if (IsListEmpty(&DeviceObject->DelayedDisconnectList)) {
  622. SMB_RELEASE_SPINLOCK(DeviceObject, Irql);
  623. DeviceObject->DisconnectWorkerRunning = FALSE;
  624. break;
  625. }
  626. entry = RemoveHeadList(&DeviceObject->DelayedDisconnectList);
  627. InsertTailList(&DeviceObject->PendingDisconnectList, entry);
  628. DeviceObject->PendingDisconnectListNumber++;
  629. SMB_RELEASE_SPINLOCK(DeviceObject, Irql);
  630. TcpContext = CONTAINING_RECORD(entry, SMB_TCP_CONTEXT, Linkage);
  631. //
  632. // FIN attacking detection and protection
  633. // The idea is couting the disconnect request pending in TCP.
  634. // If we found extraodinary high number of disconnect request pending
  635. // in TCP, use abort instead of graceful disconnect for the remaining
  636. // disconnect request.
  637. //
  638. ASSERT(DeviceObject->EnterFAPM > DeviceObject->LeaveFAPM);
  639. ASSERT(DeviceObject->LeaveFAPM > 0);
  640. if (DeviceObject->PendingDisconnectListNumber >= DeviceObject->EnterFAPM) {
  641. DeviceObject->FinAttackProtectionMode = TRUE;
  642. }
  643. if (DeviceObject->PendingDisconnectListNumber <= DeviceObject->LeaveFAPM) {
  644. DeviceObject->FinAttackProtectionMode = FALSE;
  645. }
  646. if (DeviceObject->FinAttackProtectionMode) {
  647. DisconnectFlag = TDI_DISCONNECT_ABORT;
  648. } else {
  649. DisconnectFlag = TDI_DISCONNECT_RELEASE;
  650. }
  651. status = SmbAsynchTcpDisconnect(TcpContext, DisconnectFlag);
  652. if (status == STATUS_PENDING) {
  653. continue;
  654. }
  655. //
  656. // Should be out of resources. Put it back to the DelayedDisconnectList and
  657. // wait for the next round. (Resource may be available at that time)
  658. //
  659. ASSERT(status == STATUS_INSUFFICIENT_RESOURCES);
  660. SMB_ACQUIRE_SPINLOCK(DeviceObject, Irql);
  661. RemoveEntryList(entry);
  662. InsertTailList(&DeviceObject->DelayedDisconnectList, entry);
  663. SMB_RELEASE_SPINLOCK(DeviceObject, Irql);
  664. }
  665. IoFreeWorkItem(WorkItem);
  666. SMB_ACQUIRE_SPINLOCK(DeviceObject, Irql);
  667. if (IsListEmpty(&DeviceObject->PendingDisconnectList)) {
  668. KeSetEvent(&DeviceObject->PendingDisconnectListEmptyEvent, 0, FALSE);
  669. ASSERT(DeviceObject->PendingDisconnectListNumber == 0);
  670. } else {
  671. KeResetEvent(&DeviceObject->PendingDisconnectListEmptyEvent);
  672. }
  673. SMB_RELEASE_SPINLOCK(DeviceObject, Irql);
  674. }
  675. NTSTATUS
  676. SmbQueueDisconnectWorkItem(
  677. IN PSMB_DEVICE DeviceObject,
  678. IN PSMB_TCP_CONTEXT TcpContext
  679. )
  680. {
  681. PIO_WORKITEM WorkItem;
  682. //
  683. // The DeviceObject's spinlock should be held
  684. //
  685. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  686. InsertTailList(&DeviceObject->DelayedDisconnectList, &TcpContext->Linkage);
  687. //
  688. // Be nice to others!!! Don't start too many worker threads
  689. //
  690. if (!DeviceObject->DisconnectWorkerRunning) {
  691. //
  692. // This is not a critical error.
  693. // Since we have queued the Tcp endpoint in our list, we can
  694. // handle the termporarily out of resource.
  695. // If the resource is temporarily unavailable, we can fire another
  696. // work item the next time this routine is called. The only downside
  697. // is that the disconnecting could be delayed for longer time.
  698. //
  699. WorkItem = IoAllocateWorkItem(&DeviceObject->DeviceObject);
  700. if (NULL == WorkItem) {
  701. return STATUS_INSUFFICIENT_RESOURCES;
  702. }
  703. DeviceObject->DisconnectWorkerRunning = TRUE;
  704. IoQueueWorkItem(
  705. WorkItem,
  706. (PIO_WORKITEM_ROUTINE)SmbDelayedDisconnectTcp,
  707. DelayedWorkQueue,
  708. WorkItem
  709. );
  710. }
  711. return STATUS_SUCCESS;
  712. }
  713. VOID
  714. SmbDisconnectCleanup(
  715. IN PSMB_DEVICE DeviceObject,
  716. IN PSMB_CLIENT_ELEMENT ClientObject,
  717. IN PSMB_CONNECT ConnectObject,
  718. IN PSMB_TCP_CONTEXT TcpContext,
  719. IN DWORD dwFlag,
  720. IN BOOL bWait
  721. )
  722. /*++
  723. Routine Description:
  724. Cleanup the connection object.
  725. Arguments:
  726. Return Value:
  727. --*/
  728. {
  729. PIRP PendingIrp = NULL;
  730. LIST_ENTRY PendingIrpList = { NULL };
  731. KIRQL Irql = 0;
  732. NTSTATUS status = STATUS_SUCCESS;
  733. ASSERT(ConnectObject->TcpContext == NULL);
  734. ASSERT(ClientObject != NULL);
  735. //
  736. // Grab the global lock to synchronize with TdiAcceptCompletion
  737. //
  738. SMB_ACQUIRE_SPINLOCK(DeviceObject, Irql);
  739. SMB_ACQUIRE_SPINLOCK_DPC(ClientObject);
  740. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  741. KeRemoveQueueDpc(&ConnectObject->SmbHeaderDpc);
  742. ConnectObject->State = SMB_IDLE;
  743. ConnectObject->DpcRequestQueued = FALSE;
  744. //
  745. // If the TDI_ACCEPT is still pending, remove it now.
  746. // TBD: wait for the completion of TDI accept
  747. //
  748. if (ConnectObject->PendingIRPs[SMB_PENDING_ACCEPT]) {
  749. ConnectObject->PendingIRPs[SMB_PENDING_ACCEPT] = NULL;
  750. ASSERT (EntryIsInList(&ClientObject->PendingAcceptConnection, &ConnectObject->Linkage));
  751. //
  752. // This has to be non NULL so that we can set TcpContext->Connect.UpperConenct to NULL
  753. // below and synchronize with TdiAcceptCompletion
  754. //
  755. ASSERT (TcpContext);
  756. ASSERT (ClientObject->PendingAcceptNumber > 0);
  757. ASSERT (ClientObject == SmbCfg.SmbDeviceObject->SmbServer);
  758. ASSERT (!ConnectObject->Originator);
  759. ClientObject->PendingAcceptNumber--;
  760. SmbDereferenceConnect(ConnectObject, SMB_REF_CONNECT);
  761. } else {
  762. ASSERT (!EntryIsInList(&ClientObject->PendingAcceptConnection, &ConnectObject->Linkage));
  763. }
  764. RemoveEntryList(&ConnectObject->Linkage);
  765. InsertTailList(&ClientObject->AssociatedConnection, &ConnectObject->Linkage);
  766. if (NULL != TcpContext) {
  767. TcpContext->Connect.UpperConnect = NULL;
  768. if (!bWait) {
  769. if (TcpContext->Address.AddressHandle == NULL) {
  770. SmbQueueDisconnectWorkItem (ConnectObject->Device, TcpContext);
  771. } else {
  772. //
  773. // For outbound request, we got to destroy it because
  774. // TCP doesn't support reusing.
  775. //
  776. SmbDelayedDestroyTcpContext(TcpContext);
  777. }
  778. TcpContext = NULL;
  779. }
  780. }
  781. //
  782. // Move all the pending Irps to another linked list
  783. // REVIEW: what to do with the PendingIRPs[SMB_PENDING_RECEIVE]?
  784. //
  785. InitializeListHead (&PendingIrpList);
  786. if (NULL != ConnectObject->ClientIrp && !ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE]) {
  787. InsertTailList (&PendingIrpList, &ConnectObject->ClientIrp->Tail.Overlay.ListEntry);
  788. ConnectObject->ClientIrp = NULL;
  789. }
  790. while (!IsListEmpty(&ConnectObject->RcvList)) {
  791. PLIST_ENTRY entry;
  792. entry = RemoveHeadList(&ConnectObject->RcvList);
  793. PendingIrp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  794. InsertTailList (&PendingIrpList, &PendingIrp->Tail.Overlay.ListEntry);
  795. }
  796. InitializeListHead (&ConnectObject->RcvList);
  797. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  798. SMB_RELEASE_SPINLOCK_DPC(ClientObject);
  799. SMB_RELEASE_SPINLOCK(DeviceObject, Irql);
  800. //
  801. // We have disassociate all the pending IRPs from the ConnectObject.
  802. // The ConnectObject can be reused from now on. Now we complete all
  803. // the pending IRPs.
  804. //
  805. while (!IsListEmpty(&PendingIrpList)) {
  806. PLIST_ENTRY entry;
  807. entry = RemoveHeadList(&PendingIrpList);
  808. PendingIrp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  809. IoAcquireCancelSpinLock(&Irql);
  810. IoSetCancelRoutine(PendingIrp, NULL);
  811. IoReleaseCancelSpinLock(Irql);
  812. PendingIrp->IoStatus.Status = STATUS_CONNECTION_RESET;
  813. PendingIrp->IoStatus.Information = 0;
  814. IoCompleteRequest(PendingIrp, IO_NETWORK_INCREMENT);
  815. }
  816. //
  817. // Handling the synchronous disconnect case
  818. //
  819. if (NULL != TcpContext) {
  820. ASSERT (bWait);
  821. ASSERT (dwFlag == TDI_DISCONNECT_RELEASE || dwFlag == TDI_DISCONNECT_ABORT);
  822. //
  823. // Issue synchronous disconnection
  824. //
  825. status = SmbTcpDisconnect(
  826. TcpContext,
  827. 1000, // 1 second time out
  828. dwFlag
  829. );
  830. if (STATUS_SUCCESS != status || TcpContext->Address.AddressHandle != NULL) {
  831. SmbDelayedDestroyTcpContext(TcpContext);
  832. } else {
  833. SmbFreeTcpContext(TcpContext);
  834. }
  835. }
  836. }
  837. NTSTATUS
  838. SmbDoDisconnect(
  839. PSMB_CONNECT ConnectObject
  840. )
  841. {
  842. PSMB_TCP_CONTEXT TcpContext = NULL;
  843. PSMB_CLIENT_ELEMENT ClientObject = NULL;
  844. KIRQL Irql;
  845. NTSTATUS status;
  846. PAGED_CODE();
  847. SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
  848. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  849. TcpContext = ConnectObject->TcpContext;
  850. ClientObject = ConnectObject->ClientObject;
  851. ConnectObject->TcpContext = NULL;
  852. ConnectObject->State = SMB_IDLE;
  853. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  854. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  855. SmbPrint(SMB_TRACE_CALL, ("DoDisconnect: Connect %p\n", ConnectObject));
  856. SaveDisconnectOriginator(ConnectObject, SMB_DISCONNECT_FROM_CLIENT);
  857. if (NULL != TcpContext) {
  858. ASSERT (NULL != ClientObject);
  859. //
  860. // Wait for the tcp-layer disconnect completion since
  861. // the disconnection is generated by our clients.
  862. //
  863. SmbDisconnectCleanup(ConnectObject->Device, ClientObject,
  864. ConnectObject, TcpContext, TDI_DISCONNECT_RELEASE, TRUE);
  865. ASSERT(ConnectObject->State == SMB_IDLE);
  866. }
  867. return STATUS_SUCCESS;
  868. }
  869. NTSTATUS
  870. SmbDisconnect(
  871. PSMB_DEVICE Device,
  872. PIRP Irp
  873. )
  874. /*++
  875. Routine Description:
  876. TDI_DISCONNECT
  877. To be implement.
  878. Arguments:
  879. Return Value:
  880. --*/
  881. {
  882. PIO_STACK_LOCATION IrpSp = NULL;
  883. PSMB_CONNECT ConnectObject = NULL;
  884. PAGED_CODE();
  885. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  886. ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_DISCONNECT);
  887. if (NULL == ConnectObject) {
  888. ASSERT(0);
  889. return STATUS_INVALID_HANDLE;
  890. }
  891. SmbTrace (SMB_TRACE_CONNECT, ("TDI_DISCONNECT: pIrp %p ConnOb %p", Irp, ConnectObject));
  892. SmbDoDisconnect(ConnectObject);
  893. SmbDereferenceConnect(ConnectObject, SMB_REF_DISCONNECT);
  894. return STATUS_SUCCESS;
  895. }
  896. void
  897. SmbSessionCompleteRequest(
  898. PSMB_CONNECT ConnectObject,
  899. NTSTATUS status,
  900. DWORD information
  901. )
  902. /*++
  903. Routine Description:
  904. Complete a pending session request and cleanup the connection
  905. Note: we don't cleanup the Tcp level connection here since we could be
  906. called at DISPATCH_LEVEL. Instead, we leave tcp connections alive.
  907. the cleanup will be done when the client actually disassociate or
  908. close the connection.
  909. We can reuse the tcp connection if the client reattempt to make
  910. another connection.
  911. Arguments:
  912. --*/
  913. {
  914. PIRP Irp = NULL;
  915. KIRQL Irql;
  916. PIO_STACK_LOCATION IrpSp = NULL;
  917. PSMB_CLIENT_ELEMENT ClientObject = NULL;
  918. PSMB_TCP_CONTEXT TcpContext = NULL;
  919. SmbTrace (SMB_TRACE_CONNECT, ("complete TDI_CONNECT: %p %!status!", ConnectObject, status));
  920. SmbPrint (SMB_TRACE_CONNECT, ("complete TDI_CONNECT: %p %08lx\n", ConnectObject, status));
  921. ClientObject = ConnectObject->ClientObject;
  922. ASSERT(NULL != ClientObject);
  923. if (NULL == ClientObject && status == STATUS_SUCCESS) {
  924. status = STATUS_INTERNAL_ERROR;
  925. }
  926. SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
  927. if (ClientObject) {
  928. SMB_ACQUIRE_SPINLOCK_DPC(ClientObject);
  929. }
  930. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  931. Irp = ConnectObject->PendingIRPs[SMB_PENDING_CONNECT];
  932. ConnectObject->PendingIRPs[SMB_PENDING_CONNECT] = NULL;
  933. if (status == STATUS_SUCCESS) {
  934. ConnectObject->State = SMB_CONNECTED;
  935. RemoveEntryList(&ConnectObject->Linkage);
  936. InsertTailList(&ClientObject->ActiveConnection, &ConnectObject->Linkage);
  937. TcpContext = NULL;
  938. } else {
  939. ConnectObject->State = SMB_IDLE;
  940. TcpContext = ConnectObject->TcpContext;
  941. ConnectObject->TcpContext = NULL;
  942. if (TcpContext) {
  943. TcpContext->Connect.UpperConnect = NULL;
  944. }
  945. }
  946. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  947. if (ClientObject) {
  948. SMB_RELEASE_SPINLOCK_DPC(ClientObject);
  949. }
  950. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  951. if (STATUS_CONNECTION_ACTIVE == status) {
  952. //
  953. // RDR could bugcheck if returning STATUS_CONNECTION_ACTIVE
  954. //
  955. ASSERT(0);
  956. status = STATUS_BAD_NETWORK_PATH;
  957. }
  958. //
  959. // Don't call SmbFreeOutbound() because the Tcp endpoint could be
  960. // in some inconsistent state which prohibit from being reused.
  961. // Simply destroy it!!!
  962. //
  963. SmbDelayedDestroyTcpContext(TcpContext);
  964. ASSERT (STATUS_PENDING != status);
  965. IoAcquireCancelSpinLock(&Irql);
  966. IoSetCancelRoutine(Irp, NULL);
  967. IoReleaseCancelSpinLock(Irql);
  968. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  969. Irp->IoStatus.Status = status;
  970. Irp->IoStatus.Information = information;
  971. SmbDereferenceConnect(ConnectObject, SMB_REF_CONNECT);
  972. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  973. SmbTrace (SMB_TRACE_CONNECT, ("complete TDI_CONNECT: pIrp %p ConnOb %p %!status!",
  974. Irp, ConnectObject, status));
  975. }
  976. NTSTATUS
  977. FindTdiAddress(
  978. PVOID TdiAddress,
  979. ULONG TdiAddressLength,
  980. USHORT AddressType,
  981. PVOID *AddressFound,
  982. PULONG AddressLength
  983. )
  984. /*++
  985. Routine Description:
  986. This routine search for a particular type of TDI address in a big compound address.
  987. Arguments:
  988. Return Value:
  989. STATUS_SUCCESS if we find one
  990. Otherwise fail
  991. --*/
  992. {
  993. #define TA_ADDRESS_HEADER_SIZE (FIELD_OFFSET(TA_ADDRESS,Address))
  994. int i;
  995. DWORD RemainingBufferLength;
  996. PTA_ADDRESS pAddress = NULL;
  997. TRANSPORT_ADDRESS UNALIGNED *pTransportAddr = NULL;
  998. PAGED_CODE();
  999. pTransportAddr = (PTRANSPORT_ADDRESS)TdiAddress;
  1000. if (TdiAddressLength < sizeof(pTransportAddr->TAAddressCount)) {
  1001. return STATUS_UNSUCCESSFUL;
  1002. }
  1003. RemainingBufferLength = TdiAddressLength - sizeof(pTransportAddr->TAAddressCount);
  1004. pAddress = (PTA_ADDRESS)pTransportAddr->Address;
  1005. for (i = 0; i < pTransportAddr->TAAddressCount; i++) {
  1006. //
  1007. // First, make sure we can safely access pAddress->AddressLength
  1008. //
  1009. if (RemainingBufferLength < TA_ADDRESS_HEADER_SIZE) {
  1010. return STATUS_INVALID_ADDRESS_COMPONENT;
  1011. }
  1012. RemainingBufferLength -= TA_ADDRESS_HEADER_SIZE;
  1013. if (RemainingBufferLength < pAddress->AddressLength) {
  1014. return STATUS_INVALID_ADDRESS_COMPONENT;
  1015. }
  1016. if (AddressType == pAddress->AddressType) {
  1017. *AddressFound = pAddress->Address;
  1018. *AddressLength = pAddress->AddressLength;
  1019. return STATUS_SUCCESS;
  1020. }
  1021. RemainingBufferLength -= pAddress->AddressLength;
  1022. pAddress = (PTA_ADDRESS)(((PUCHAR)pAddress) + pAddress->AddressLength + TA_ADDRESS_HEADER_SIZE);
  1023. }
  1024. return STATUS_UNSUCCESSFUL;
  1025. }