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.

12014 lines
387 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Name.c
  5. Abstract:
  6. This file implements Tdi interface into the Top of NBT. In the NT
  7. implementation, ntisol.c calls these routines after extracting the
  8. relevent information from the Irp passed in from the Io subsystem.
  9. Author:
  10. Jim Stewart (Jimst) 10-2-92
  11. Revision History:
  12. --*/
  13. #include "precomp.h" // procedure headings
  14. #ifndef VXD
  15. #ifdef RASAUTODIAL
  16. #include <acd.h>
  17. #include <acdapi.h>
  18. #include <tcpinfo.h>
  19. #include <tdiinfo.h>
  20. #endif // RASAUTODIAL
  21. #include "name.tmh"
  22. #endif
  23. //
  24. // Allocate storage for the configuration information and setup a ptr to
  25. // it.
  26. //
  27. tNBTCONFIG NbtConfig;
  28. tNBTCONFIG *pNbtGlobConfig = &NbtConfig;
  29. BOOLEAN CachePrimed;
  30. //
  31. // This structure is used to store name query and registration statistics
  32. //
  33. tNAMESTATS_INFO NameStatsInfo;
  34. #ifndef VXD
  35. //
  36. // this tracks the original File system process that Nbt was booted by, so
  37. // that handles can be created and destroyed in that process
  38. //
  39. PEPROCESS NbtFspProcess;
  40. #endif
  41. //
  42. // this describes whether we are a Bnode, Mnode, MSnode or Pnode
  43. //
  44. USHORT RegistryNodeType;
  45. USHORT NodeType;
  46. //
  47. // this is used to track the memory allocated for datagram sends
  48. //
  49. ULONG NbtMemoryAllocated;
  50. // this is used to track used trackers to help solve cases where they all
  51. // are used.
  52. //
  53. //#if DBG
  54. LIST_ENTRY UsedTrackers;
  55. //#endif
  56. #ifdef VXD
  57. ULONG DefaultDisconnectTimeout;
  58. #else
  59. LARGE_INTEGER DefaultDisconnectTimeout;
  60. #endif
  61. // ************* REMOVE LATER *****************88
  62. BOOLEAN StreamsStack;
  63. #ifdef DBG
  64. //
  65. // Imported routines.
  66. //
  67. #endif
  68. NTSTATUS
  69. NbtpConnectCompletionRoutine(
  70. PDEVICE_OBJECT pDeviceObject,
  71. PIRP pIrp,
  72. PVOID pCompletionContext
  73. );
  74. //
  75. // Function prototypes for functions local to this file
  76. //
  77. VOID
  78. CleanupFromRegisterFailed(
  79. IN PUCHAR pNameRslv,
  80. IN tCLIENTELE *pClientEle
  81. );
  82. VOID
  83. SendDgramContinue(
  84. IN PVOID pContext,
  85. IN NTSTATUS status
  86. );
  87. VOID
  88. CTECountedAllocMem(
  89. PVOID *pBuffer,
  90. ULONG Size
  91. );
  92. VOID
  93. CTECountedFreeMem(
  94. IN PVOID pBuffer,
  95. IN ULONG Size,
  96. IN BOOLEAN fJointLockHeld
  97. );
  98. VOID
  99. SendNextDgramToGroup(
  100. IN tDGRAM_SEND_TRACKING *pTracker,
  101. IN NTSTATUS status
  102. );
  103. VOID
  104. SendDgramCompletion(
  105. IN PVOID pContext,
  106. IN NTSTATUS status,
  107. IN ULONG lInfo);
  108. VOID
  109. DgramSendCleanupTracker(
  110. IN tDGRAM_SEND_TRACKING *pTracker,
  111. IN NTSTATUS status,
  112. IN BOOLEAN fJointLockHeld
  113. );
  114. VOID
  115. SessionSetupContinue(
  116. IN PVOID pContext,
  117. IN NTSTATUS status
  118. );
  119. VOID
  120. SessionStartupCompletion(
  121. IN PVOID pContext,
  122. IN NTSTATUS status,
  123. IN ULONG lInfo);
  124. VOID
  125. SendNodeStatusContinue(
  126. IN PVOID pContext,
  127. IN NTSTATUS status
  128. );
  129. NTSTATUS
  130. SendToResolvingName(
  131. IN tNAMEADDR *pNameAddr,
  132. IN PCHAR pName,
  133. IN CTELockHandle OldIrq,
  134. IN tDGRAM_SEND_TRACKING *pTracker,
  135. IN PVOID QueryCompletion
  136. );
  137. NTSTATUS
  138. StartSessionTimer(
  139. tDGRAM_SEND_TRACKING *pTracker,
  140. tCONNECTELE *pConnEle
  141. );
  142. VOID
  143. QueryNameCompletion(
  144. IN PVOID pContext,
  145. IN NTSTATUS status
  146. );
  147. #ifndef VXD
  148. VOID
  149. NTClearFindNameInfo(
  150. tDGRAM_SEND_TRACKING *pTracker,
  151. PIRP *ppClientIrp,
  152. PIRP pIrp,
  153. PIO_STACK_LOCATION pIrpSp
  154. );
  155. #endif // !VXD
  156. NTSTATUS
  157. FindNameOrQuery(
  158. IN PUCHAR pName,
  159. IN tDEVICECONTEXT *pDeviceContext,
  160. IN PVOID QueryCompletion,
  161. IN tDGRAM_SEND_TRACKING *pTracker,
  162. IN ULONG NameFlags,
  163. OUT tIPADDRESS *IpAddress,
  164. OUT tNAMEADDR **pNameAddr,
  165. IN ULONG NameReferenceContext,
  166. IN BOOLEAN DgramSend
  167. );
  168. #ifdef RASAUTODIAL
  169. extern BOOLEAN fAcdLoadedG;
  170. extern ACD_DRIVER AcdDriverG;
  171. VOID
  172. NbtRetryPreConnect(
  173. IN BOOLEAN fSuccess,
  174. IN PVOID *pArgs
  175. );
  176. VOID
  177. NbtCancelPreConnect(
  178. IN PDEVICE_OBJECT pDeviceObject,
  179. IN PIRP pIrp
  180. );
  181. VOID
  182. NbtRetryPostConnect(
  183. IN BOOLEAN fSuccess,
  184. IN PVOID *pArgs
  185. );
  186. BOOLEAN
  187. NbtAttemptAutoDial(
  188. IN tCONNECTELE *pConnEle,
  189. IN PVOID pTimeout,
  190. IN PTDI_CONNECTION_INFORMATION pCallInfo,
  191. IN PIRP pIrp,
  192. IN ULONG ulFlags,
  193. IN ACD_CONNECT_CALLBACK pProc
  194. );
  195. VOID
  196. NbtNoteNewConnection(
  197. IN tNAMEADDR *pNameAddr,
  198. IN ULONG IPAddress
  199. );
  200. #endif // RASAUTODIAL
  201. NTSTATUS
  202. NbtConnectCommon(
  203. IN TDI_REQUEST *pRequest,
  204. IN PVOID pTimeout,
  205. IN PTDI_CONNECTION_INFORMATION pCallInfo,
  206. IN PIRP pIrp
  207. );
  208. NTSTATUS
  209. GetListOfAllAddrs(
  210. IN tNAMEADDR *pNameAddr,
  211. IN tNAMEADDR *p1CNameAddr,
  212. IN tIPADDRESS **ppIpBuffer,
  213. IN ULONG *pNumAddrs
  214. );
  215. BOOL
  216. IsLocalAddress(
  217. tIPADDRESS IpAddress
  218. );
  219. BOOL
  220. IsSmbBoundToOutgoingInterface(
  221. IN tIPADDRESS IpAddress
  222. );
  223. //******************* Pageable Routine Declarations ****************
  224. #ifdef ALLOC_PRAGMA
  225. #pragma CTEMakePageable(PAGE, NbtOpenConnection)
  226. #pragma CTEMakePageable(PAGE, NbtSendDatagram)
  227. #pragma CTEMakePageable(PAGE, BuildSendDgramHdr)
  228. #pragma CTEMakePageable(PAGE, DelayedNbtResyncRemoteCache)
  229. #pragma CTEMakePageable(PAGE, NbtQueryFindName)
  230. #pragma CTEMakePageable(PAGE, NbtCloseAddress)
  231. #pragma CTEMakePageable(PAGE, NbtCloseConnection)
  232. #endif
  233. //******************* Pageable Routine Declarations ****************
  234. //----------------------------------------------------------------------------
  235. NTSTATUS
  236. PickBestAddress(
  237. IN tNAMEADDR *pNameAddr,
  238. IN tDEVICECONTEXT *pDeviceContext,
  239. OUT tIPADDRESS *pIpAddress
  240. )
  241. /*++
  242. Routine Description:
  243. This Routine picks the best address on a name based on strictness of Source addressing specified
  244. -- MUST be called with the JointLock held!
  245. Arguments:
  246. Return Value:
  247. NTSTATUS - status of the request
  248. --*/
  249. {
  250. tDEVICECONTEXT *pThisDeviceContext;
  251. LIST_ENTRY *pHead, *pEntry;
  252. BOOLEAN fFreeGroupList = FALSE;
  253. tIPADDRESS IpAddress = 0;
  254. tIPADDRESS *pIpNbtGroupList = NULL;
  255. CHECK_PTR (pNameAddr);
  256. CHECK_PTR (pDeviceContext);
  257. if (pNameAddr->Verify == REMOTE_NAME)
  258. {
  259. //
  260. // Check if this is a pre-loaded name!
  261. //
  262. if (pNameAddr->NameAddFlags & NAME_RESOLVED_BY_LMH_P)
  263. {
  264. IpAddress = pNameAddr->IpAddress;
  265. pIpNbtGroupList = pNameAddr->pLmhSvcGroupList;
  266. }
  267. //
  268. // See if we can find the preferred address
  269. //
  270. else if (((IsDeviceNetbiosless(pDeviceContext)) &&
  271. (pNameAddr->pRemoteIpAddrs && pNameAddr->pRemoteIpAddrs[0].IpAddress)) ||
  272. ((!IsDeviceNetbiosless(pDeviceContext)) &&
  273. (pNameAddr->RemoteCacheLen > pDeviceContext->AdapterNumber) &&
  274. (pNameAddr->AdapterMask & pDeviceContext->AdapterMask)))
  275. {
  276. IpAddress = pNameAddr->pRemoteIpAddrs[pDeviceContext->AdapterNumber].IpAddress;
  277. pIpNbtGroupList = pNameAddr->pRemoteIpAddrs[pDeviceContext->AdapterNumber].pOrigIpAddrs;
  278. }
  279. //
  280. // If strict source routing was not set, then pick the last updated address
  281. //
  282. if ((!NbtConfig.ConnectOnRequestedInterfaceOnly) &&
  283. (!IpAddress) && (!pIpNbtGroupList))
  284. {
  285. if (STATUS_SUCCESS == GetListOfAllAddrs(pNameAddr, NULL, &pIpNbtGroupList, NULL))
  286. {
  287. fFreeGroupList = TRUE;
  288. }
  289. else
  290. {
  291. pIpNbtGroupList = NULL; // for safety
  292. }
  293. }
  294. //
  295. // If this was a Group name, then IpAddress can be 0!
  296. //
  297. if ((!IpAddress) && (pIpNbtGroupList)) {
  298. //
  299. // Pick the first non-zero address from the group list
  300. //
  301. int i;
  302. for (i = 0; pIpNbtGroupList[i] != (tIPADDRESS) -1; i++) {
  303. if (pIpNbtGroupList[i]) {
  304. IpAddress = pIpNbtGroupList[i];
  305. break;
  306. }
  307. }
  308. }
  309. if (fFreeGroupList)
  310. {
  311. CTEMemFree(pIpNbtGroupList);
  312. }
  313. }
  314. else
  315. {
  316. ASSERT (pNameAddr->Verify == LOCAL_NAME);
  317. //
  318. // For local names, first check if the name is registered on this device
  319. //
  320. if ((!(IsDeviceNetbiosless(pDeviceContext)) && (pDeviceContext->IpAddress) &&
  321. (pNameAddr->AdapterMask & pDeviceContext->AdapterMask)) ||
  322. ((IsDeviceNetbiosless(pDeviceContext)) &&
  323. (pNameAddr->NameFlags & NAME_REGISTERED_ON_SMBDEV)))
  324. {
  325. IpAddress = pDeviceContext->IpAddress;
  326. }
  327. //
  328. // If the strict source routing option is not set, then return the first valid local address
  329. //
  330. else if (!NbtConfig.ConnectOnRequestedInterfaceOnly)
  331. {
  332. //
  333. // Find the first device with a valid IP address that this name is registered on
  334. //
  335. pHead = pEntry = &NbtConfig.DeviceContexts;
  336. while ((pEntry = pEntry->Flink) != pHead)
  337. {
  338. pThisDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  339. if ((pThisDeviceContext->IpAddress) &&
  340. (pThisDeviceContext->AdapterMask & pNameAddr->AdapterMask))
  341. {
  342. IpAddress = pThisDeviceContext->IpAddress;
  343. pNameAddr->IpAddress = pThisDeviceContext->IpAddress;
  344. break;
  345. }
  346. }
  347. //
  348. // If we failed to find the name registered on any of the legacy
  349. // devices, then we should check if the name is registered on the
  350. // SMBDevice and if so, return its IP address.
  351. //
  352. if ((!IpAddress) &&
  353. (pNbtSmbDevice) &&
  354. (pNameAddr->NameFlags & NAME_REGISTERED_ON_SMBDEV))
  355. {
  356. IpAddress = pNbtSmbDevice->IpAddress;
  357. }
  358. }
  359. }
  360. if ((IpAddress) && (pIpAddress))
  361. {
  362. *pIpAddress = IpAddress;
  363. return (STATUS_SUCCESS);
  364. }
  365. return (STATUS_UNSUCCESSFUL);
  366. }
  367. //----------------------------------------------------------------------------
  368. VOID
  369. RemoveDuplicateAddresses(
  370. tIPADDRESS *pIpAddrBuffer,
  371. ULONG *pNumAddrs
  372. )
  373. {
  374. ULONG NumAddrs = *pNumAddrs;
  375. ULONG i, j;
  376. for (i=0; i<NumAddrs; i++) {
  377. for (j=i+1; j<NumAddrs; j++) {
  378. if (pIpAddrBuffer[i] == pIpAddrBuffer[j]) {
  379. NumAddrs--;
  380. pIpAddrBuffer[j] = pIpAddrBuffer[NumAddrs];
  381. j--;
  382. }
  383. }
  384. }
  385. IF_DBG(NBT_DEBUG_NAMESRV)
  386. KdPrint(("Nbt.RemoveDuplicateAddresses: NumAddresses = <%d> --> <%d>\n", *pNumAddrs, NumAddrs));
  387. *pNumAddrs = NumAddrs;
  388. }
  389. VOID
  390. CountAndCopyAddrs(
  391. tIPADDRESS *pIpAddrSrc,
  392. tIPADDRESS *pIpAddrDest,
  393. ULONG *pNumAddrs
  394. )
  395. {
  396. ULONG NumAddrs = *pNumAddrs;
  397. if (pIpAddrSrc)
  398. {
  399. while (*pIpAddrSrc != (ULONG)-1)
  400. {
  401. if (*pIpAddrSrc)
  402. {
  403. if (pIpAddrDest)
  404. {
  405. pIpAddrDest[NumAddrs] = *pIpAddrSrc;
  406. }
  407. NumAddrs++;
  408. }
  409. pIpAddrSrc++;
  410. }
  411. }
  412. *pNumAddrs = NumAddrs;
  413. }
  414. //----------------------------------------------------------------------------
  415. NTSTATUS
  416. GetListOfAllAddrs(
  417. IN tNAMEADDR *pNameAddr,
  418. IN tNAMEADDR *p1CNameAddr,
  419. IN tIPADDRESS **ppIpBuffer,
  420. IN ULONG *pNumAddrs
  421. )
  422. {
  423. ULONG i;
  424. tIPADDRESS *pIpBuffer;
  425. tIPADDRESS *pIpAddr;
  426. ULONG NumAddrs = 0;
  427. BOOLEAN fAddBcastAddr = FALSE;
  428. *ppIpBuffer = NULL;
  429. if (pNumAddrs)
  430. {
  431. *pNumAddrs = 0;
  432. }
  433. //
  434. // First count all the addresses
  435. //
  436. if (pNameAddr->pLmhSvcGroupList) // if the name was Preloaded from LmHosts
  437. {
  438. ASSERT(pNameAddr->NameTypeState & NAMETYPE_INET_GROUP);
  439. CountAndCopyAddrs (pNameAddr->pLmhSvcGroupList, NULL, &NumAddrs);
  440. }
  441. else
  442. {
  443. if (pNameAddr->IpAddress)
  444. {
  445. NumAddrs++;
  446. }
  447. //
  448. // RemoteCacheLen will be 0 if we had failed to allocate the pRemoteIpAddrs structure earlier
  449. //
  450. for (i=0; i<pNameAddr->RemoteCacheLen; i++)
  451. {
  452. CountAndCopyAddrs (pNameAddr->pRemoteIpAddrs[i].pOrigIpAddrs, NULL, &NumAddrs);
  453. if (pNameAddr->pRemoteIpAddrs[i].IpAddress)
  454. {
  455. NumAddrs++;
  456. }
  457. }
  458. }
  459. if (p1CNameAddr)
  460. {
  461. //
  462. // This would a name that was added through LmHosts, so it will
  463. // not have been resolved-per-interface from Wins!
  464. //
  465. ASSERT((p1CNameAddr->NameTypeState & NAMETYPE_INET_GROUP) && (!p1CNameAddr->pRemoteIpAddrs));
  466. CountAndCopyAddrs (p1CNameAddr->pLmhSvcGroupList, NULL, &NumAddrs);
  467. }
  468. if (!NumAddrs)
  469. {
  470. return (STATUS_BAD_NETWORK_PATH);
  471. }
  472. NumAddrs++; // For the terminating address
  473. if ((pNameAddr->NameTypeState & NAMETYPE_INET_GROUP) &&
  474. (!(pNameAddr->fPreload)))
  475. {
  476. // Add the bcast address
  477. fAddBcastAddr = TRUE;
  478. NumAddrs++; // For the bcast address
  479. }
  480. if (!(pIpBuffer = NbtAllocMem((NumAddrs*sizeof(tIPADDRESS)),NBT_TAG('N'))))
  481. {
  482. return(STATUS_INSUFFICIENT_RESOURCES);
  483. }
  484. //
  485. // Now copy all the addresses starting with the broadcast address if necessary
  486. //
  487. NumAddrs = 0;
  488. if (fAddBcastAddr)
  489. {
  490. pIpBuffer[0] = 0;
  491. NumAddrs++;
  492. }
  493. if (pNameAddr->pLmhSvcGroupList) // if the name was Preloaded from LmHosts
  494. {
  495. CountAndCopyAddrs (pNameAddr->pLmhSvcGroupList, pIpBuffer, &NumAddrs);
  496. }
  497. else
  498. {
  499. if (pNameAddr->IpAddress)
  500. {
  501. pIpBuffer[NumAddrs] = pNameAddr->IpAddress;
  502. NumAddrs++;
  503. }
  504. for (i=0; i<pNameAddr->RemoteCacheLen; i++)
  505. {
  506. CountAndCopyAddrs (pNameAddr->pRemoteIpAddrs[i].pOrigIpAddrs, pIpBuffer, &NumAddrs);
  507. if (pNameAddr->pRemoteIpAddrs[i].IpAddress)
  508. {
  509. pIpBuffer[NumAddrs] = pNameAddr->pRemoteIpAddrs[i].IpAddress;
  510. NumAddrs++;
  511. }
  512. }
  513. }
  514. if (p1CNameAddr)
  515. {
  516. CountAndCopyAddrs (p1CNameAddr->pLmhSvcGroupList, pIpBuffer, &NumAddrs);
  517. }
  518. RemoveDuplicateAddresses(pIpBuffer, &NumAddrs);
  519. pIpBuffer[NumAddrs] = (tIPADDRESS)-1;
  520. *ppIpBuffer = pIpBuffer;
  521. if (pNumAddrs)
  522. {
  523. *pNumAddrs = NumAddrs;
  524. }
  525. return (STATUS_SUCCESS);
  526. }
  527. VOID
  528. FilterIpAddrsForDevice(
  529. IN tIPADDRESS *pIpAddr,
  530. IN tDEVICECONTEXT *pDeviceContext,
  531. IN ULONG *pNumAddrs
  532. )
  533. {
  534. ULONG i;
  535. ULONG Interface, Metric;
  536. ULONG NumAddrs = *pNumAddrs;
  537. ASSERT (NumAddrs > 0);
  538. if (NbtConfig.SendDgramOnRequestedInterfaceOnly)
  539. {
  540. for (i=1; i<NumAddrs; i++)
  541. {
  542. pDeviceContext->pFastQuery(ntohl(pIpAddr[i]), &Interface, &Metric);
  543. if (Interface != pDeviceContext->IPInterfaceContext)
  544. {
  545. pIpAddr[i] = pIpAddr[NumAddrs-1];
  546. NumAddrs--;
  547. i--;
  548. }
  549. }
  550. *pNumAddrs = NumAddrs;
  551. pIpAddr[NumAddrs] = (tIPADDRESS) -1;
  552. }
  553. }
  554. //----------------------------------------------------------------------------
  555. NTSTATUS
  556. NbtOpenAddress(
  557. IN TDI_REQUEST *pRequest,
  558. IN TA_ADDRESS *pTaAddress,
  559. IN tIPADDRESS IpAddress,
  560. IN tDEVICECONTEXT *pContext,
  561. IN PVOID pIrp)
  562. /*++
  563. Routine Description:
  564. This Routine handles opening an address for a Client.
  565. Arguments:
  566. Return Value:
  567. NTSTATUS - status of the request
  568. --*/
  569. {
  570. NTSTATUS status;
  571. tADDRESSELE *pAddrElement;
  572. tCLIENTELE *pClientEle;
  573. USHORT uAddrType;
  574. CTELockHandle OldIrq;
  575. CTELockHandle OldIrq1;
  576. PUCHAR pNameRslv;
  577. tNAMEADDR *pNameAddr;
  578. COMPLETIONCLIENT pClientCompletion;
  579. PVOID Context;
  580. tTIMERQENTRY *pTimer;
  581. BOOLEAN MultiHomedReRegister = FALSE;
  582. BOOLEAN DontIncrement= FALSE;
  583. ULONG TdiAddressType;
  584. UCHAR *BroadcastName = "\x2a\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0";
  585. LIST_ENTRY *pClientEntry;
  586. tCLIENTELE *pClientEleTemp;
  587. BOOLEAN fFirstClientOnDevice = TRUE;
  588. ASSERT(pTaAddress);
  589. if (!IpAddress)
  590. {
  591. //
  592. // when there is no ip address yet, use the Loop back address as
  593. // a default rather than null, since null tells NbtRegisterName
  594. // that the address is already in the name table and it only needs
  595. // to be reregistered.
  596. //
  597. IpAddress = LOOP_BACK;
  598. }
  599. TdiAddressType = pTaAddress->AddressType;
  600. switch (TdiAddressType)
  601. {
  602. case TDI_ADDRESS_TYPE_NETBIOS:
  603. {
  604. PTDI_ADDRESS_NETBIOS pNetbiosAddress = (PTDI_ADDRESS_NETBIOS)pTaAddress->Address;
  605. uAddrType = pNetbiosAddress->NetbiosNameType;
  606. pNameRslv = pNetbiosAddress->NetbiosName;
  607. break;
  608. }
  609. #ifndef VXD
  610. case TDI_ADDRESS_TYPE_NETBIOS_EX:
  611. {
  612. // The NETBIOS_EX address passed in will have two components,
  613. // an Endpoint name as well as the NETBIOS address.
  614. // In this implementation we ignore the second
  615. // component and register the Endpoint name as a netbios
  616. // address.
  617. PTDI_ADDRESS_NETBIOS_EX pNetbiosExAddress = (PTDI_ADDRESS_NETBIOS_EX)pTaAddress->Address;
  618. uAddrType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
  619. pNameRslv = pNetbiosExAddress->EndpointName;
  620. break;
  621. }
  622. #endif
  623. default:
  624. return STATUS_INVALID_ADDRESS_COMPONENT;
  625. }
  626. //
  627. // If the name is a Broadcast name, it can only be opened as a Group name
  628. //
  629. if ((CTEMemEqu (BroadcastName, pNameRslv, NETBIOS_NAME_SIZE)) &&
  630. (uAddrType != NBT_GROUP))
  631. {
  632. KdPrint (("Nbt.NbtOpenAddress: Warning: Opening broadcast name as Groupname!\n"));
  633. uAddrType = NBT_GROUP;
  634. }
  635. IF_DBG(NBT_DEBUG_NAMESRV)
  636. KdPrint(("Nbt.NbtOpenAddress: Name=<%-16.16s:%x>, pDevice=<%p>\n",
  637. pNameRslv, pNameRslv[15], pContext));
  638. //
  639. // be sure the broadcast name has 15 zeroes after it
  640. //
  641. if ((pNameRslv[0] == '*') && (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS))
  642. {
  643. CTEZeroMemory(&pNameRslv[1],NETBIOS_NAME_SIZE-1);
  644. }
  645. // this synchronizes access to the local name table when a new name
  646. // is registered. Basically it will not let the second registrant through
  647. // until the first has put the name into the local table (i.e.
  648. // NbtRegisterName has returned )
  649. //
  650. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  651. // see if the name is registered on the local node.. we call the hash
  652. // table function directly rather than using findname, because find name
  653. // checks the state of the name too. We want to know if the name is in
  654. // the table at all, and don't care if it is still resolving.
  655. //
  656. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  657. pNameAddr = NULL;
  658. status = FindInHashTable (pNbtGlobConfig->pLocalHashTbl, pNameRslv, NbtConfig.pScope, &pNameAddr);
  659. //
  660. // the name could be in the hash table, but the address element deleted
  661. //
  662. if (!NT_SUCCESS(status) || !pNameAddr->pAddressEle)
  663. {
  664. //
  665. // pNameAddr->pAddressEle is NULL <==> the Name is currently being released
  666. //
  667. if (pNameAddr)
  668. {
  669. //
  670. // Check if the name is about to be released on this adapter
  671. //
  672. if (pNameAddr->AdapterMask & pContext->AdapterMask)
  673. {
  674. pNameAddr->AdapterMask &= ~pContext->AdapterMask;
  675. }
  676. //
  677. // Check if the name is currently being released on this adapter
  678. //
  679. else if (pNameAddr->ReleaseMask & pContext->AdapterMask)
  680. {
  681. // Set the ReleaseMask bit to 0 so that the Timeout routine
  682. // does does not send this release out on the wire again
  683. //
  684. pNameAddr->ReleaseMask &= ~pContext->AdapterMask;
  685. }
  686. }
  687. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  688. // open the name since it could not be found
  689. //
  690. // first of all allocate memory for the address block
  691. //
  692. status = STATUS_INSUFFICIENT_RESOURCES;
  693. if (pAddrElement = (tADDRESSELE *) NbtAllocMem(sizeof(tADDRESSELE),NBT_TAG('C')))
  694. {
  695. CTEZeroMemory(pAddrElement,sizeof(tADDRESSELE));
  696. InitializeListHead(&pAddrElement->Linkage);
  697. InitializeListHead(&pAddrElement->ClientHead);
  698. CTEInitLock(&pAddrElement->LockInfo.SpinLock);
  699. #if DBG
  700. pAddrElement->LockInfo.LockNumber = ADDRESS_LOCK;
  701. #endif
  702. pAddrElement->AddressType = TdiAddressType;
  703. if ((uAddrType == NBT_UNIQUE ) || (uAddrType == NBT_QUICK_UNIQUE))
  704. {
  705. pAddrElement->NameType = NBT_UNIQUE;
  706. }
  707. else
  708. {
  709. pAddrElement->NameType = NBT_GROUP;;
  710. }
  711. pAddrElement->Verify = NBT_VERIFY_ADDRESS;
  712. NBT_REFERENCE_ADDRESS (pAddrElement, REF_ADDR_NEW_CLIENT);
  713. // create client block and link to addresslist. This allows multiple
  714. // clients to open the same address - for example a group name must
  715. // be able to handle multiple clients, each receiving datagrams to it.
  716. //
  717. if (pClientEle = NbtAllocateClientBlock(pAddrElement, pContext))
  718. {
  719. pClientEle->AddressType = TdiAddressType;
  720. pClientEle->pIrp = pIrp; // Track Irp -- complete it when the name registration completes
  721. #ifndef VXD
  722. // set the share access ( NT only ) - security descriptor stuff
  723. if (pIrp)
  724. {
  725. status = NTSetSharedAccess(pContext,pIrp,pAddrElement);
  726. }
  727. else
  728. {
  729. status = STATUS_SUCCESS;
  730. }
  731. if (!NT_SUCCESS(status))
  732. {
  733. // unable to set the share access correctly so release the
  734. // address object and the client block connected to it
  735. NbtFreeAddressObj(pAddrElement);
  736. NbtFreeClientObj(pClientEle);
  737. CTEExReleaseResource(&NbtConfig.Resource);
  738. return(status);
  739. }
  740. // fill in the context values passed back to the client. These must
  741. // be done before the name is registered on the network because the
  742. // registration can succeed (or fail) before this routine finishes).
  743. // Since this routine can be called by NBT itself, pIrp may not be set,
  744. // so check for it.
  745. //
  746. if (pIrp)
  747. {
  748. NTSetFileObjectContexts( pClientEle->pIrp,(PVOID)pClientEle, (PVOID)(NBT_ADDRESS_TYPE));
  749. }
  750. #endif //!VXD
  751. // pass back the client block address as a handle for future reference
  752. // to the client
  753. pRequest->Handle.AddressHandle = (PVOID)pClientEle;
  754. // then add it to name service local name Q, passing the address of
  755. // the block as a context value ( so that subsequent finds return the
  756. // context value.
  757. // we need to know if the name is a group name or a unique name.
  758. // This registration may take some time so we return STATUS_PENDING
  759. // to the client
  760. //
  761. NBT_REFERENCE_ADDRESS (pAddrElement, REF_ADDR_REGISTER_NAME);
  762. status = NbtRegisterName (NBT_LOCAL,
  763. IpAddress,
  764. pNameRslv,
  765. NULL,
  766. pClientEle, // context value
  767. (PVOID)NbtRegisterCompletion, // completion routine for
  768. uAddrType, // Name Srv to call
  769. pContext);
  770. //
  771. // ret status could be either status pending or status success since Quick
  772. // names return success - or status failure
  773. //
  774. if (!NT_SUCCESS(status))
  775. {
  776. if (pIrp)
  777. {
  778. pClientEle->pIrp = NULL;
  779. NTClearFileObjectContext(pIrp);
  780. }
  781. ASSERT(pAddrElement->RefCount == 2);
  782. CTEExReleaseResource(&NbtConfig.Resource);
  783. NBT_DEREFERENCE_CLIENT (pClientEle);
  784. NBT_DEREFERENCE_ADDRESS (pAddrElement, REF_ADDR_REGISTER_NAME);
  785. return (status);
  786. }
  787. NbtTrace(NBT_TRACE_NAMESRV, ("Client open address %!NBTNAME!<%02x> ClientEle=%p",
  788. pNameRslv, (unsigned)pNameRslv[15], pClientEle));
  789. // link the address element to the head of the address list
  790. // The Joint Lock protects this operation.
  791. ExInterlockedInsertTailList(&NbtConfig.AddressHead,
  792. &pAddrElement->Linkage,
  793. &NbtConfig.JointLock.LockInfo.SpinLock);
  794. NBT_DEREFERENCE_ADDRESS (pAddrElement, REF_ADDR_REGISTER_NAME);
  795. } // if pClientEle
  796. else
  797. {
  798. NbtFreeAddressObj(pAddrElement);
  799. pAddrElement = NULL;
  800. }
  801. } // if pAddrElement
  802. }
  803. else
  804. {
  805. pAddrElement = (tADDRESSELE *)pNameAddr->pAddressEle;
  806. //
  807. // increment here before releasing the spinlock so that a name
  808. // release done cannot free pAddrElement.
  809. //
  810. NBT_REFERENCE_ADDRESS (pAddrElement, REF_ADDR_NEW_CLIENT);
  811. #ifndef VXD
  812. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  813. // check the shared access of the name - this check must be done
  814. // at Irl = 0, so no spin locks held
  815. //
  816. if (pIrp)
  817. {
  818. status = NTCheckSharedAccess (pContext, pIrp, (tADDRESSELE *)pNameAddr->pAddressEle);
  819. }
  820. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  821. CTESpinLock(pAddrElement,OldIrq1);
  822. #else
  823. //
  824. // For the Vxd, we don't allow multiple names in the local name table.
  825. // In NT, this is prevented on a per process basis by the Netbios
  826. // driver. If the name is being deregistered (conflict) then allow
  827. // the client to reopen the name
  828. //
  829. if ( !(pNameAddr->NameTypeState & STATE_CONFLICT))
  830. {
  831. status = STATUS_UNSUCCESSFUL;
  832. }
  833. #endif
  834. //
  835. // Write the correct Ip address to the table incase this
  836. // was a group name and has now changed to a unique
  837. // name, but don't overwrite with the loop back address because
  838. // that means that the adapter does not have an address yet.
  839. // For Group names the Ip address stays as 0, so we know to do a
  840. // broadcast.
  841. //
  842. if ((IpAddress != LOOP_BACK) &&
  843. (pNameAddr->NameTypeState & NAMETYPE_UNIQUE))
  844. {
  845. pNameAddr->IpAddress = IpAddress;
  846. }
  847. // multihomed hosts register the same unique name on several adapters.
  848. // NT DOES allow a client to share a unique name, so we must NOT
  849. // run this next code if the NT check has passed!!
  850. //
  851. if (!NT_SUCCESS(status))
  852. {
  853. //
  854. // if this is a unique name being registered on another adapter
  855. // then allow it to occur - the assumption is that the same
  856. // client is registering on more than one adapter all at once,
  857. // rather than two different clients.
  858. //
  859. if (NbtConfig.MultiHomed && (!(pNameAddr->AdapterMask & pContext->AdapterMask)))
  860. {
  861. status = STATUS_SUCCESS;
  862. }
  863. //
  864. // check if this is a client trying to add the permanent name,
  865. // since that name will fail the security check
  866. // We allow a single client to use the permanent name - since its
  867. // a unique name it will fail the Vxd check too.
  868. //
  869. else if (CTEMemEqu(&pNameAddr->Name[10], &pContext->MacAddress.Address[0], sizeof(tMAC_ADDRESS)))
  870. {
  871. // check if there is just one element on the client list. If so
  872. // then the permanent name is not being used yet - i.e. it has
  873. // been opened once by the NBT code itself so the node will
  874. // answer Nodestatus requests to the name, but no client
  875. // has opened it yet
  876. //
  877. if (pAddrElement->ClientHead.Flink->Flink == &pAddrElement->ClientHead)
  878. {
  879. status = STATUS_SUCCESS;
  880. }
  881. }
  882. else if ((pNameAddr->NameTypeState & STATE_CONFLICT))
  883. {
  884. // check if the name is in the process of being deregisterd -
  885. // STATE_CONFLICT - in this case allow it to carry on and take over
  886. // name.
  887. //
  888. status = STATUS_SUCCESS;
  889. }
  890. }
  891. if ((NT_SUCCESS(status)) &&
  892. (pNameAddr->NameTypeState & STATE_CONFLICT))
  893. {
  894. // this could either be a real conflict or a name being deleted on
  895. // the net, so stop any timer associated with the name release
  896. // and carry on
  897. //
  898. if (pTimer = pNameAddr->pTimer)
  899. {
  900. // this routine puts the timer block back on the timer Q, and
  901. // handles race conditions to cancel the timer when the timer
  902. // is expiring.
  903. pNameAddr->pTimer = NULL;
  904. status = StopTimer(pTimer,&pClientCompletion,&Context);
  905. // there is a client's irp waiting for the name release to finish
  906. // so complete that irp back to them
  907. if (pClientCompletion)
  908. {
  909. //
  910. // NOTE****
  911. // We must clear the AdapterMask so that NameReleaseDone
  912. // does not try to release the name on another net card
  913. // for the multihomed case.
  914. //
  915. CHECK_PTR(pNameAddr);
  916. CTESpinFree(pAddrElement,OldIrq1);
  917. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  918. (*pClientCompletion)(Context,STATUS_SUCCESS);
  919. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  920. CTESpinLock(pAddrElement,OldIrq1);
  921. }
  922. CHECK_PTR(pNameAddr);
  923. }
  924. //
  925. // this allows another client to use a name almost immediately
  926. // after the first one releases the name on the net. However
  927. // if the first client has not released the name yet, and is
  928. // still on the clienthead list, then the name will not be
  929. // reregistered, and this current registration will fail because
  930. // the name state is conflict. That check is done below.
  931. //
  932. if (IsListEmpty(&pAddrElement->ClientHead))
  933. {
  934. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  935. pNameAddr->NameTypeState |= STATE_RESOLVED;
  936. status = STATUS_SUCCESS;
  937. MultiHomedReRegister = TRUE;
  938. IF_DBG(NBT_DEBUG_NAMESRV)
  939. KdPrint(("Nbt.NbtOpenAddress: Conflict State, re-registering name on net\n"));
  940. }
  941. else
  942. {
  943. #if 0
  944. //
  945. // Don't log the event:
  946. // The current name state is already in CONFLICTED state,
  947. // we should have already logged an event when we change
  948. // its state into CONFLICTED.
  949. //
  950. // set status that indicates someone else has the name on the
  951. // network.
  952. //
  953. if (!IS_MESSENGER_NAME(pNameRslv))
  954. {
  955. //
  956. // We need to Q this event to a Worker thread since it
  957. // requires the name to be converted to Unicode
  958. //
  959. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT);
  960. status = NTQueueToWorkerThread(NULL, DelayedNbtLogDuplicateNameEvent,
  961. (PVOID) pNameAddr,
  962. IntToPtr(IpAddress),
  963. IntToPtr(0x106),
  964. pContext,
  965. TRUE);
  966. if (!NT_SUCCESS(status))
  967. {
  968. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT, TRUE);
  969. NbtLogEvent (EVENT_NBT_DUPLICATE_NAME, IpAddress, 0x106);
  970. }
  971. }
  972. #endif
  973. status = STATUS_DUPLICATE_NAME;
  974. }
  975. }
  976. else if (NT_SUCCESS(status))
  977. {
  978. // name already exists - is open; allow only another client creating a
  979. // name of the same type
  980. //
  981. if ((uAddrType == NBT_UNIQUE) || ( uAddrType == NBT_QUICK_UNIQUE))
  982. {
  983. if (!(pNameAddr->NameTypeState & NAMETYPE_UNIQUE))
  984. {
  985. status = STATUS_SHARING_VIOLATION;
  986. }
  987. }
  988. else if (!(pNameAddr->NameTypeState & NAMETYPE_GROUP))
  989. {
  990. status = STATUS_SHARING_VIOLATION;
  991. }
  992. }
  993. else
  994. {
  995. status = STATUS_SHARING_VIOLATION;
  996. }
  997. // if everything is OK, create client block and link to addresslist
  998. // pass back the client block address as a handle for future reference
  999. // to the client
  1000. if ((NT_SUCCESS(status)) &&
  1001. (!(pClientEle = NbtAllocateClientBlock (pAddrElement, pContext))))
  1002. {
  1003. status = STATUS_INSUFFICIENT_RESOURCES;
  1004. }
  1005. //
  1006. // check for a failure, if so , then return
  1007. //
  1008. if (!NT_SUCCESS(status))
  1009. {
  1010. CHECK_PTR(pRequest);
  1011. pRequest->Handle.AddressHandle = NULL;
  1012. CTESpinFree(pAddrElement,OldIrq1);
  1013. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1014. NBT_DEREFERENCE_ADDRESS (pAddrElement, REF_ADDR_NEW_CLIENT);
  1015. CTEExReleaseResource(&NbtConfig.Resource);
  1016. return(status);
  1017. }
  1018. // we need to track the Irp so that when the name registration
  1019. // completes, we can complete the Irp.
  1020. pClientEle->pIrp = pIrp;
  1021. pClientEle->AddressType = TdiAddressType;
  1022. pRequest->Handle.AddressHandle = (PVOID)pClientEle;
  1023. // fill in the context values passed back to the client. These must
  1024. // be done before the name is registered on the network because the
  1025. // registration can succeed (or fail) before this routine finishes).
  1026. // Since this routine can be called by NBT itself, there may not be an
  1027. // irp to fill in, so check first.
  1028. if (pIrp)
  1029. {
  1030. #ifndef VXD
  1031. NTSetFileObjectContexts( pClientEle->pIrp,(PVOID)pClientEle, (PVOID)(NBT_ADDRESS_TYPE));
  1032. #endif
  1033. }
  1034. //
  1035. // See if this is not the first Client on this Device
  1036. //
  1037. pClientEntry = &pAddrElement->ClientHead;
  1038. while ((pClientEntry = pClientEntry->Flink) != &pAddrElement->ClientHead)
  1039. {
  1040. pClientEleTemp = CONTAINING_RECORD (pClientEntry,tCLIENTELE,Linkage);
  1041. if ((pClientEleTemp != pClientEle) &&
  1042. (pClientEleTemp->pDeviceContext == pContext))
  1043. {
  1044. fFirstClientOnDevice = FALSE;
  1045. break;
  1046. }
  1047. }
  1048. if (fFirstClientOnDevice)
  1049. {
  1050. if (IsDeviceNetbiosless(pContext))
  1051. {
  1052. pNameAddr->NameFlags |= NAME_REGISTERED_ON_SMBDEV;
  1053. }
  1054. else
  1055. {
  1056. //
  1057. // turn on the adapter's bit in the adapter Mask and set the
  1058. // re-register flag (if the name is not resolving already) so
  1059. // we register the name out the new adapter.
  1060. //
  1061. pNameAddr->AdapterMask |= pContext->AdapterMask;
  1062. if (pNameAddr->NameTypeState & STATE_RESOLVED)
  1063. {
  1064. MultiHomedReRegister = TRUE;
  1065. }
  1066. }
  1067. }
  1068. else
  1069. {
  1070. // the adapter bit is already on in the pAddressEle, so
  1071. // this must be another client registering the same name,
  1072. // therefore turn on the MultiClient boolean so that the DgramRcv
  1073. // code will know to activate its multiple client rcv code.
  1074. //
  1075. pAddrElement->MultiClients = TRUE;
  1076. }
  1077. //
  1078. // check the state of the entry in the table. If the state is
  1079. // resolved then complete the request now,otherwise we cannot complete
  1080. // this request yet... i.e. we return Pending.
  1081. //
  1082. if (((pNameAddr->NameTypeState & STATE_RESOLVED) &&
  1083. (!MultiHomedReRegister)))
  1084. {
  1085. // basically we are all done now, so just return status success
  1086. // to the client
  1087. //
  1088. status = STATUS_SUCCESS;
  1089. CHECK_PTR(pClientEle);
  1090. pClientEle->pIrp = NULL;
  1091. CTESpinFree(pAddrElement,OldIrq1);
  1092. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1093. pClientEle->WaitingForRegistration = FALSE;
  1094. }
  1095. else
  1096. {
  1097. IF_DBG(NBT_DEBUG_NAMESRV)
  1098. KdPrint(("Nbt.NbtOpenAddress: Waiting for prev registration- state=%x, ReRegister=%x\n",
  1099. pNameAddr->NameTypeState, MultiHomedReRegister));
  1100. // we need to track the Irp so that when the name registration
  1101. // completes, we can complete the Irp.
  1102. pClientEle->pIrp = pIrp;
  1103. CTESpinFree(pAddrElement,OldIrq1);
  1104. if (MultiHomedReRegister)
  1105. {
  1106. // this flag is used by RegisterCompletion ( when true )
  1107. pClientEle->WaitingForRegistration = FALSE;
  1108. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1109. IF_DBG(NBT_DEBUG_NAMESRV)
  1110. KdPrint(("Nbt.NbtOpenAddress: Resolved State=%x, ReRegister=%x\n",
  1111. pNameAddr->NameTypeState, MultiHomedReRegister));
  1112. // we need to re-register the name on the net because it is not
  1113. // currently in the resolved state and there is no timer active
  1114. // We do that by calling this routine with the IpAddress set to NULL
  1115. // to signal that routine not to put the name in the hash table
  1116. // since it is already there.
  1117. //
  1118. status = NbtRegisterName (NBT_LOCAL,
  1119. 0, // set to zero to signify already in tbl
  1120. pNameRslv,
  1121. pNameAddr,
  1122. pClientEle,
  1123. (PVOID)NbtRegisterCompletion,
  1124. uAddrType,
  1125. pContext);
  1126. if (!NT_SUCCESS(status))
  1127. {
  1128. if (pIrp)
  1129. {
  1130. pClientEle->pIrp = NULL;
  1131. NTClearFileObjectContext(pIrp);
  1132. }
  1133. CTEExReleaseResource(&NbtConfig.Resource);
  1134. NBT_DEREFERENCE_CLIENT (pClientEle);
  1135. return (status);
  1136. }
  1137. }
  1138. else
  1139. {
  1140. pClientEle->WaitingForRegistration = TRUE;
  1141. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1142. // for multihomed, a second registration on a second adapter
  1143. // at the same time as the first adapter is registering is
  1144. // delayed until the first completes, then its registration
  1145. // proceeds - See RegistrationCompletion below.
  1146. //
  1147. status = STATUS_PENDING;
  1148. }
  1149. }
  1150. }
  1151. CTEExReleaseResource(&NbtConfig.Resource);
  1152. #ifdef _PNP_POWER_
  1153. //
  1154. // See if we need to set the Wakeup pattern on this Device
  1155. //
  1156. if ((NT_SUCCESS(status)) &&
  1157. (*pNameRslv != '*') &&
  1158. (pNameRslv[NETBIOS_NAME_SIZE-1] == SPECIAL_SERVER_SUFFIX))
  1159. {
  1160. pContext->NumServers++;
  1161. CheckSetWakeupPattern (pContext, pNameRslv, TRUE);
  1162. }
  1163. #endif
  1164. return(status);
  1165. }
  1166. //----------------------------------------------------------------------------
  1167. NTSTATUS
  1168. NbtRegisterCompletion(
  1169. IN tCLIENTELE *pClientEleIn,
  1170. IN NTSTATUS status
  1171. )
  1172. /*++
  1173. Routine Description
  1174. This routine handles completing a name registration request. The namesrv.c
  1175. Name server calls this routine when it has registered a name. The address
  1176. of this routine is passed to the Local Name Server in the NbtRegisterName
  1177. request.
  1178. The idea is to complete the irps that are waiting on the name registration,
  1179. one per client element.
  1180. When a DHCP reregister occurs there is no client irp so the name is
  1181. not actually deleted from the table when a bad status is passed to this
  1182. routine. Hence the need for the DhcpRegister flag to change the code
  1183. path for that case.
  1184. Arguments:
  1185. Return Values:
  1186. NTSTATUS - status of the request
  1187. --*/
  1188. {
  1189. LIST_ENTRY *pHead;
  1190. LIST_ENTRY *pEntry;
  1191. CTELockHandle OldIrq;
  1192. CTELockHandle OldIrq1;
  1193. tADDRESSELE *pAddress;
  1194. tDEVICECONTEXT *pDeviceContext;
  1195. tNAMEADDR *pNameAddr;
  1196. tCLIENTELE *pClientEle;
  1197. LIST_ENTRY TempList;
  1198. ULONG Count=0;
  1199. InitializeListHead(&TempList);
  1200. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1201. pAddress = pClientEleIn->pAddress;
  1202. pDeviceContext = pClientEleIn->pDeviceContext;
  1203. CTESpinLock(pAddress,OldIrq);
  1204. // Several Clients can open the same address at the same time, so when the
  1205. // name registration completes, it should complete all of them!!
  1206. // increment the reference count so that the hash table entry cannot
  1207. // disappear while we are using it.
  1208. //
  1209. NBT_REFERENCE_ADDRESS (pAddress, REF_ADDR_REG_COMPLETION);
  1210. pNameAddr = pAddress->pNameAddr;
  1211. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  1212. pNameAddr->pTimer = NULL; // Bug #: 231693
  1213. // if the registration failed or a previous registration failed for the
  1214. // multihomed case, deny the client the name
  1215. //
  1216. if ((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT))
  1217. {
  1218. pNameAddr->NameTypeState |= STATE_RESOLVED;
  1219. }
  1220. else
  1221. {
  1222. pNameAddr->NameTypeState |= STATE_CONFLICT;
  1223. pNameAddr->ConflictMask |= pDeviceContext->AdapterMask;
  1224. status = STATUS_DUPLICATE_NAME;
  1225. }
  1226. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1227. //
  1228. // find all clients that are attached to the address and complete the
  1229. // I/O requests, if they are on the same adapter that the name was
  1230. // just registered against, if successful. For failure cases complete
  1231. // all irps with the failure code - i.e. failure to register a name on
  1232. // one adapter fails all adapters.
  1233. //
  1234. FailRegistration:
  1235. pHead = &pAddress->ClientHead;
  1236. pEntry = pHead->Flink;
  1237. while (pEntry != pHead)
  1238. {
  1239. // complete the I/O
  1240. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  1241. pEntry = pEntry->Flink;
  1242. //
  1243. // It is possible for the second registration of a name to fail so
  1244. // we do not want to attempt to return the irp on the first
  1245. // registration, which has completed ok already. Therefore
  1246. // if the status is failure, then only complete those clients that
  1247. // have the WaitingForReg... bit set
  1248. //
  1249. // if it is the client ele passed in, or one on the same device context
  1250. // that is waiting for a name registration, or it is a failure...
  1251. // AND the client IRP is still valid then return the Irp.
  1252. //
  1253. if ((pClientEle->pIrp) &&
  1254. ((pClientEle == pClientEleIn) ||
  1255. ((pClientEle->pDeviceContext == pDeviceContext) && (pClientEle->WaitingForRegistration)) ||
  1256. ((status != STATUS_SUCCESS) && pClientEle->WaitingForRegistration)))
  1257. {
  1258. // for failed registrations, remove the client from the address list
  1259. // since we are going to delete him below.
  1260. if (!NT_SUCCESS(status))
  1261. {
  1262. // turn off the adapter bit so we know not to use this name with this
  1263. // adapter - since it is a failure, turn off all adapter bits
  1264. // since a single name registration failure means all registrations
  1265. // fail.
  1266. CHECK_PTR(pNameAddr);
  1267. pNameAddr->AdapterMask = 0;
  1268. // setting this to null prevents CloseAddress and CleanupAddress
  1269. // from accessing pAddress and crashing.
  1270. //
  1271. CHECK_PTR(pClientEle);
  1272. pClientEle->pAddress = NULL;
  1273. // clear the ptr to the ClientEle that NbtRegisterName put into
  1274. // the irp ( i.e. the context values are cleared )
  1275. //
  1276. #ifndef VXD
  1277. NTSetFileObjectContexts(pClientEle->pIrp,NULL,NULL);
  1278. #endif
  1279. RemoveEntryList(&pClientEle->Linkage);
  1280. }
  1281. ASSERT(pClientEle->pIrp);
  1282. pClientEle->WaitingForRegistration = FALSE;
  1283. #ifndef VXD
  1284. // put all irps that have to be completed on a separate list
  1285. // and then complete later after releaseing the spin lock.
  1286. //
  1287. InsertTailList(&TempList,&pClientEle->pIrp->Tail.Overlay.ListEntry);
  1288. #else
  1289. //
  1290. // pAddress gets set in the name table for this NCB
  1291. //
  1292. Count++;
  1293. CTESpinFree(pAddress,OldIrq1);
  1294. CTEIoComplete( pClientEle->pIrp, status, (ULONG) pClientEle ) ;
  1295. CTESpinLock(pAddress,OldIrq1);
  1296. #endif
  1297. CHECK_PTR(pClientEle);
  1298. pClientEle->pIrp = NULL ;
  1299. // free the client object memory
  1300. if (!NT_SUCCESS(status))
  1301. {
  1302. NbtFreeClientObj(pClientEle);
  1303. }
  1304. }
  1305. }
  1306. CTESpinFree(pAddress,OldIrq1);
  1307. #ifndef VXD
  1308. //
  1309. // for the NT case where MP - ness can disrupt the list at any
  1310. // time, scan the whole list above without releasing the spin lock,
  1311. // and then complete the irps collected here
  1312. //
  1313. while (!IsListEmpty(&TempList))
  1314. {
  1315. PIRP pIrp;
  1316. pEntry = RemoveHeadList(&TempList);
  1317. pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
  1318. CTEIoComplete(pIrp,status,0);
  1319. Count++;
  1320. }
  1321. #endif
  1322. // if the registration failed, do one more dereference of the address
  1323. // to remove the refcount added by this client. This may cause a name
  1324. // release on the network if there are no other clients registering
  1325. // the name.
  1326. //
  1327. if (!NT_SUCCESS(status))
  1328. {
  1329. //
  1330. // dereference the address the same number of times that we have
  1331. // returned failed registrations since each reg. referenced pAddress
  1332. // once
  1333. //
  1334. while (Count--)
  1335. {
  1336. NBT_DEREFERENCE_ADDRESS (pAddress, REF_ADDR_NEW_CLIENT);
  1337. }
  1338. }
  1339. else
  1340. {
  1341. USHORT uAddrType;
  1342. CTESpinLock(pAddress,OldIrq1);
  1343. // go through the clients and see if any are waiting to register
  1344. // a name. This happens in the multihomed case, but should not
  1345. // happen in the single adapter case.
  1346. //
  1347. pHead = &pAddress->ClientHead;
  1348. pEntry = pHead->Flink;
  1349. while (pEntry != pHead)
  1350. {
  1351. // complete the I/O
  1352. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  1353. pEntry = pEntry->Flink;
  1354. if (pClientEle->WaitingForRegistration)
  1355. {
  1356. ULONG SaveState;
  1357. pClientEle->WaitingForRegistration = FALSE;
  1358. if (pNameAddr->NameTypeState & NAMETYPE_UNIQUE)
  1359. {
  1360. uAddrType = NBT_UNIQUE;
  1361. }
  1362. else
  1363. uAddrType = NBT_GROUP;
  1364. //
  1365. // preserve the "QUICK"ness
  1366. //
  1367. if (pNameAddr->NameTypeState & NAMETYPE_QUICK)
  1368. {
  1369. uAddrType |= NBT_QUICK_UNIQUE;
  1370. }
  1371. IF_DBG(NBT_DEBUG_NAMESRV)
  1372. KdPrint(("Nbt.NbtRegisterCompletion: Registering next name state= %X,%15s<%X>\n",
  1373. pNameAddr->NameTypeState,pNameAddr->Name,pNameAddr->Name[15]));
  1374. SaveState = pNameAddr->NameTypeState;
  1375. CTESpinFree(pAddress,OldIrq1);
  1376. // this may be a multihomed host, with another name registration
  1377. // pending out another adapter, so start that registration.
  1378. status = NbtRegisterName (NBT_LOCAL,
  1379. 0, // set to zero to signify already in tbl
  1380. pNameAddr->Name,
  1381. pNameAddr,
  1382. pClientEle,
  1383. (PVOID)NbtRegisterCompletion,
  1384. uAddrType,
  1385. pClientEle->pDeviceContext);
  1386. CTESpinLock(pAddress,OldIrq1);
  1387. // since nbtregister will set the state to Resolving, when
  1388. // it might be resolved already on one adapter.
  1389. pNameAddr->NameTypeState = SaveState;
  1390. if (!NT_SUCCESS(status))
  1391. {
  1392. // if this fails for some reason, then fail any other name
  1393. // registrations pending. - the registername call should not
  1394. // fail unless we are out of resources.
  1395. pClientEle->WaitingForRegistration = TRUE;
  1396. goto FailRegistration;
  1397. }
  1398. // just register one name at a time, unless we get immediate success
  1399. else if (status == STATUS_PENDING)
  1400. {
  1401. break;
  1402. }
  1403. else // SUCCESS
  1404. {
  1405. CTESpinFree(pAddress,OldIrq1);
  1406. CTEIoComplete(pClientEle->pIrp,status,0);
  1407. pClientEle->pIrp = NULL;
  1408. CTESpinLock(pAddress,OldIrq1);
  1409. }
  1410. }
  1411. }
  1412. CTESpinFree(pAddress,OldIrq1);
  1413. }
  1414. if (!NT_SUCCESS(status))
  1415. {
  1416. //
  1417. // Go through all the Clients still attached, and reset their
  1418. // AdapterMasks since we could have removed them
  1419. //
  1420. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1421. CTESpinLock(pAddress,OldIrq1);
  1422. pEntry = pHead = &pAddress->ClientHead;
  1423. while ((pEntry = pEntry->Flink) != pHead)
  1424. {
  1425. pClientEle = CONTAINING_RECORD (pEntry,tCLIENTELE,Linkage);
  1426. if (!IsDeviceNetbiosless(pClientEle->pDeviceContext))
  1427. {
  1428. pNameAddr->AdapterMask |= pClientEle->pDeviceContext->AdapterMask;
  1429. }
  1430. }
  1431. CTESpinFree(pAddress,OldIrq1);
  1432. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1433. }
  1434. // this decrements for the RefCount++ done in this routine.
  1435. NBT_DEREFERENCE_ADDRESS (pAddress, REF_ADDR_REG_COMPLETION);
  1436. return(STATUS_SUCCESS);
  1437. }
  1438. //----------------------------------------------------------------------------
  1439. NTSTATUS
  1440. NbtOpenConnection(
  1441. IN TDI_REQUEST *pRequest,
  1442. IN CONNECTION_CONTEXT ConnectionContext,
  1443. IN tDEVICECONTEXT *pDeviceContext
  1444. )
  1445. /*++
  1446. Routine Description
  1447. This routine handles creating a connection object for the client. It
  1448. passes back a ptr to the connection so that OS specific portions of the
  1449. data structure can be filled in.
  1450. Arguments:
  1451. Return Values:
  1452. pConnectEle - ptr to the allocated connection data structure
  1453. TDI_STATUS - status of the request
  1454. --*/
  1455. {
  1456. NTSTATUS status = STATUS_SUCCESS ;
  1457. tCONNECTELE *pConnEle;
  1458. CTEPagedCode();
  1459. // Acquire this resource to co-ordinate with DHCP changing the IP address
  1460. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  1461. if ((!pDeviceContext->pSessionFileObject) ||
  1462. (!(pConnEle = (tCONNECTELE *)NbtAllocMem(sizeof(tCONNECTELE),NBT_TAG('D')))))
  1463. {
  1464. CTEExReleaseResource(&NbtConfig.Resource);
  1465. return(STATUS_INSUFFICIENT_RESOURCES);
  1466. }
  1467. IF_DBG(NBT_DEBUG_NAMESRV)
  1468. KdPrint(("Nbt.NbtOpenConnection: pConnEle = <%x>\n",pConnEle));
  1469. // This ensures that all BOOLEAN values begin with a FALSE value among other things.
  1470. CTEZeroMemory(pConnEle,sizeof(tCONNECTELE));
  1471. CTEInitLock(&pConnEle->LockInfo.SpinLock);
  1472. #if DBG
  1473. pConnEle->LockInfo.LockNumber = CONNECT_LOCK;
  1474. #endif
  1475. // initialize lists to empty
  1476. InitializeListHead(&pConnEle->RcvHead);
  1477. pConnEle->Verify = NBT_VERIFY_CONNECTION;
  1478. NBT_REFERENCE_CONNECTION (pConnEle, REF_CONN_CREATE); // so we don't delete the connection
  1479. SET_STATE_UPPER (pConnEle, NBT_IDLE);
  1480. pConnEle->pDeviceContext = pDeviceContext;
  1481. pConnEle->ConnectContext = ConnectionContext; // used in various event calls (eg. Receive, Disconnect)
  1482. //
  1483. // for each connection the client(s) open, open a connection to the transport
  1484. // so that we can accept one to one from the transport.
  1485. #ifndef VXD
  1486. //
  1487. // Allocate an MDL to be used for partial Mdls
  1488. // The length of the Mdl is set to 64K(MAXUSHORT) so that there are enough
  1489. // pfns in the Mdl to map a large buffer.
  1490. //
  1491. // use pConnEle as the Virtual address, since it doesn't matter
  1492. // because it will be overwritten when the partial Mdl is created.
  1493. //
  1494. if (pConnEle->pNewMdl = IoAllocateMdl ((PVOID)pConnEle, MAXUSHORT, FALSE, FALSE, NULL))
  1495. #endif
  1496. {
  1497. //
  1498. // allocate memory for the lower connection block.
  1499. //
  1500. status = NbtOpenAndAssocConnection(pDeviceContext, NULL, NULL, '2');
  1501. if (NT_SUCCESS(status))
  1502. {
  1503. // link on to list of open connections for this device so that we
  1504. // know how many open connections there are at any time (if we need to know)
  1505. // This linkage is only in place until the client does an associate, then
  1506. // the connection is unlinked from here and linked to the client ConnectHead.
  1507. //
  1508. ExInterlockedInsertHeadList(&pDeviceContext->UpConnectionInUse,
  1509. &pConnEle->Linkage,
  1510. &NbtConfig.JointLock.LockInfo.SpinLock);
  1511. // return the pointer to the block to the client as the connection id
  1512. pRequest->Handle.ConnectionContext = (PVOID)pConnEle;
  1513. CTEExReleaseResource(&NbtConfig.Resource);
  1514. NbtTrace(NBT_TRACE_OUTBOUND, ("New connection: pConnEle=%p pLowerConn=%p pDeviceContext=%p",
  1515. pConnEle, pConnEle->pLowerConnId, pConnEle->pDeviceContext));
  1516. return(STATUS_SUCCESS);
  1517. }
  1518. #ifndef VXD
  1519. IoFreeMdl(pConnEle->pNewMdl);
  1520. #endif
  1521. }
  1522. #ifndef VXD
  1523. else
  1524. {
  1525. // ASSERTMSG("Nbt:Unable to allocate a MDL!!\n",0);
  1526. status = STATUS_INSUFFICIENT_RESOURCES;
  1527. }
  1528. #endif // !VXD
  1529. FreeConnectionObj(pConnEle);
  1530. CTEExReleaseResource(&NbtConfig.Resource);
  1531. return(status);
  1532. }
  1533. //----------------------------------------------------------------------------
  1534. NTSTATUS
  1535. NbtOpenAndAssocConnection(
  1536. IN tDEVICECONTEXT *pDeviceContext,
  1537. IN tCONNECTELE *pConnEle,
  1538. OUT tLOWERCONNECTION **ppLowerConn,
  1539. IN UCHAR Identifier
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. This Routine handles associating a Net Bios name with an open connection.
  1544. In order to coordinate with ZwClose(hSession) in CloseAddressesWithTransport/ntutil.c,
  1545. this routine should be called with NbtConfig.Resource exclusively locked.
  1546. Arguments:
  1547. Return Value:
  1548. NTSTATUS - status of the request
  1549. --*/
  1550. {
  1551. NTSTATUS status;
  1552. NTSTATUS Locstatus;
  1553. BOOLEAN Attached=FALSE;
  1554. tLOWERCONNECTION *pLowerConn;
  1555. PDEVICE_OBJECT pDeviceObject;
  1556. HANDLE hSession;
  1557. ULONG Id = 0;
  1558. UCHAR *Id1 = (UCHAR *) &Id;
  1559. TCP_REQUEST_SET_INFORMATION_EX *pTcpSetInfo;
  1560. struct TCPSocketOption *pSockOption;
  1561. ULONG BufferLength;
  1562. if (ppLowerConn)
  1563. {
  1564. *ppLowerConn = NULL;
  1565. }
  1566. Id1[1] = 'L';
  1567. Id1[0] = Identifier;
  1568. if (!(pLowerConn = (tLOWERCONNECTION *) NbtAllocMem(sizeof(tLOWERCONNECTION), NBT_TAG2(Id))))
  1569. {
  1570. return (STATUS_INSUFFICIENT_RESOURCES);
  1571. }
  1572. CHECK_PTR(pLowerConn);
  1573. CTEZeroMemory((PVOID)pLowerConn,sizeof(tLOWERCONNECTION));
  1574. CTEAttachFsp(&Attached, REF_FSP_CONN);
  1575. status = NbtTdiOpenConnection(pLowerConn,pDeviceContext);
  1576. if (!NT_SUCCESS(status))
  1577. {
  1578. KdPrint(("Nbt.NbtOpenAndAssocConnection: NbtTdiOpenConnection returned ERROR=%x\n", status));
  1579. CTEDetachFsp(Attached, REF_FSP_CONN);
  1580. CTEMemFree(pLowerConn);
  1581. return(status);
  1582. }
  1583. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE);
  1584. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_ASSOC_CONNECTION);
  1585. if (pConnEle)
  1586. {
  1587. //
  1588. // Open an address object (aka port)
  1589. //
  1590. //
  1591. // until the correct state proc is set (i.e.Outbound), reject any data
  1592. // (in other words, don't let this field stay NULL!)
  1593. //
  1594. SetStateProc (pLowerConn, RejectAnyData);
  1595. status = NbtTdiOpenAddress (&pLowerConn->AddrFileHandle,
  1596. &pDeviceObject, // dummy argument, not used here
  1597. &pLowerConn->pAddrFileObject,
  1598. pDeviceContext,
  1599. (USHORT) 0, // any port
  1600. pDeviceContext->IpAddress,
  1601. TCP_FLAG);
  1602. hSession = pLowerConn->AddrFileHandle;
  1603. }
  1604. else
  1605. {
  1606. #ifndef VXD
  1607. hSession = pDeviceContext->hSession;
  1608. #else
  1609. hSession = (HANDLE) pDeviceContext->pSessionFileObject); // Address handle stored in pFileObjects
  1610. #endif
  1611. }
  1612. /*
  1613. * hSession could be NULL if the IP address is being released.
  1614. */
  1615. if (hSession == NULL) {
  1616. status = STATUS_UNSUCCESSFUL;
  1617. }
  1618. if (NT_SUCCESS(status))
  1619. {
  1620. // associate with 139 or 445 session address
  1621. status = NbtTdiAssociateConnection (pLowerConn->pFileObject, hSession);
  1622. if (NT_SUCCESS(status))
  1623. {
  1624. ASSERT(pLowerConn->RefCount == 2);
  1625. //
  1626. // Disable nagling on this connection
  1627. //
  1628. if (!pDeviceContext->EnableNagling) {
  1629. NbtSetTcpInfo (pLowerConn->FileHandle, TCP_SOCKET_NODELAY, INFO_TYPE_CONNECTION, (ULONG)TRUE);
  1630. }
  1631. if (pConnEle)
  1632. {
  1633. pLowerConn->pUpperConnection = pConnEle;
  1634. ExInterlockedInsertTailList (&pDeviceContext->LowerConnection, // put on active connections Q
  1635. &pLowerConn->Linkage,
  1636. &pDeviceContext->LockInfo.SpinLock);
  1637. }
  1638. else
  1639. {
  1640. InterlockedIncrement (&pDeviceContext->NumFreeLowerConnections);
  1641. ExInterlockedInsertTailList (&pDeviceContext->LowerConnFreeHead, // put on free list
  1642. &pLowerConn->Linkage,
  1643. &pDeviceContext->LockInfo.SpinLock);
  1644. }
  1645. InterlockedIncrement (&pDeviceContext->TotalLowerConnections);
  1646. CTEDetachFsp(Attached, REF_FSP_CONN);
  1647. if (ppLowerConn)
  1648. {
  1649. *ppLowerConn = pLowerConn;
  1650. }
  1651. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_ASSOC_CONNECTION, FALSE);
  1652. return status;
  1653. }
  1654. KdPrint(("Nbt.NbtOpenAndAssocConnection: NbtTdiAssociateConnection returned ERROR=%x\n", status));
  1655. }
  1656. else
  1657. {
  1658. KdPrint(("Nbt.NbtOpenAddress: NbtTdiOpenConnection returned ERROR=%x\n", status));
  1659. }
  1660. /*
  1661. * NBT_DEREFERENCE_LOWERCONN will decrease the TotalLowerConnections
  1662. * Without the following InterlockedIncrement, we could under-count
  1663. * the actual # of Lower Connection.
  1664. */
  1665. InterlockedIncrement (&pDeviceContext->TotalLowerConnections);
  1666. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_ASSOC_CONNECTION, FALSE);
  1667. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, FALSE);
  1668. CTEDetachFsp(Attached, REF_FSP_CONN);
  1669. return(status);
  1670. }
  1671. //----------------------------------------------------------------------------
  1672. NTSTATUS
  1673. NbtAssociateAddress(
  1674. IN TDI_REQUEST *pRequest,
  1675. IN tCLIENTELE *pClientHandle,
  1676. IN PVOID pIrp
  1677. )
  1678. /*++
  1679. Routine Description:
  1680. This Routine handles associating a Net Bios name with an open connection.
  1681. Arguments:
  1682. Return Value:
  1683. NTSTATUS - status of the request
  1684. --*/
  1685. {
  1686. tCONNECTELE *pConnEle;
  1687. NTSTATUS status;
  1688. CTELockHandle OldIrq;
  1689. CTELockHandle OldIrq1;
  1690. CTELockHandle OldIrq2;
  1691. CTELockHandle OldIrq3;
  1692. pConnEle = pRequest->Handle.ConnectionContext;
  1693. CTESpinLock(&NbtConfig.JointLock,OldIrq3);
  1694. // Need code here to check if the address has been registered on the net
  1695. // yet and if not, then this could must wait till then , then to the
  1696. // associate *TODO*
  1697. CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status) // check connection for validity
  1698. CTEVerifyHandle(pClientHandle,NBT_VERIFY_CLIENT,tCLIENTELE,&status) // check client for validity now!
  1699. CTESpinLock(pClientHandle->pDeviceContext,OldIrq2);
  1700. CTESpinLock(pClientHandle,OldIrq);
  1701. CTESpinLock(pConnEle,OldIrq1);
  1702. if ((pConnEle->state != NBT_IDLE) ||
  1703. (!NBT_VERIFY_HANDLE (pConnEle, NBT_VERIFY_CONNECTION)) || // NBT_VERIFY_CONNECTION_DOWN if cleaned up
  1704. (!NBT_VERIFY_HANDLE (pClientHandle, NBT_VERIFY_CLIENT))) // NBT_VERIFY_CLIENT_DOWN if cleaned up
  1705. {
  1706. // the connection is in use, so reject the associate attempt
  1707. CTESpinFree(pConnEle,OldIrq1);
  1708. CTESpinFree(pClientHandle,OldIrq);
  1709. CTESpinFree(pClientHandle->pDeviceContext,OldIrq2);
  1710. CTESpinFree(&NbtConfig.JointLock,OldIrq3);
  1711. return(STATUS_INVALID_HANDLE);
  1712. }
  1713. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  1714. // link the connection to the client so we can find the client, given
  1715. // the connection.
  1716. pConnEle->pClientEle = (PVOID)pClientHandle;
  1717. NbtTrace(NBT_TRACE_OUTBOUND, ("Associate: pConnEle %p pDeviceContext %p Client %p",
  1718. pConnEle, pConnEle->pDeviceContext, pConnEle->pClientEle));
  1719. // there can be multiple connections hooked to each client block - i.e.
  1720. // multiple connections per address per client. This allows the client
  1721. // to find its connections.
  1722. //
  1723. // first unlink from the device context UpconnectionsInUse, which was linked
  1724. // when the connection was created.
  1725. RemoveEntryList(&pConnEle->Linkage);
  1726. InsertTailList(&pClientHandle->ConnectHead,&pConnEle->Linkage);
  1727. CTESpinFree(pConnEle,OldIrq1);
  1728. CTESpinFree(pClientHandle,OldIrq);
  1729. CTESpinFree(pClientHandle->pDeviceContext,OldIrq2);
  1730. CTESpinFree(&NbtConfig.JointLock,OldIrq3);
  1731. return(STATUS_SUCCESS);
  1732. }
  1733. //----------------------------------------------------------------------------
  1734. NTSTATUS
  1735. NbtDisassociateAddress(
  1736. IN TDI_REQUEST *pRequest
  1737. )
  1738. /*++
  1739. Routine Description:
  1740. This Routine handles disassociating a Net Bios name with an open connection.
  1741. The expectation is that the
  1742. client will follow with a NtClose which will do the work in Cleanup and
  1743. Close Connection. Since not all clients call this it is duplicate work
  1744. to put some code here to. The Rdr always calls NtClose after calling
  1745. this.
  1746. Arguments:
  1747. Return Value:
  1748. NTSTATUS - status of the request
  1749. --*/
  1750. {
  1751. tCONNECTELE *pConnEle;
  1752. tCLIENTELE *pClientEle;
  1753. NTSTATUS status;
  1754. CTELockHandle OldIrq;
  1755. CTELockHandle OldIrq1;
  1756. CTELockHandle OldIrq2;
  1757. tDEVICECONTEXT *pDeviceContext;
  1758. TDI_REQUEST Request;
  1759. ULONG Flags;
  1760. LIST_ENTRY TempList;
  1761. PLIST_ENTRY pHead,pEntry;
  1762. tLISTENREQUESTS *pListen;
  1763. pConnEle = pRequest->Handle.ConnectionContext;
  1764. // check the connection element for validity
  1765. CHECK_PTR(pConnEle);
  1766. if (!NBT_VERIFY_HANDLE2(pConnEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
  1767. {
  1768. ASSERT(0);
  1769. return (STATUS_INVALID_HANDLE);
  1770. }
  1771. IF_DBG(NBT_DEBUG_NAMESRV)
  1772. KdPrint(("Nbt.NbtDisassociateAddress: State = %X\n",pConnEle->state));
  1773. Flags = TDI_DISCONNECT_RELEASE;
  1774. switch (pConnEle->state)
  1775. {
  1776. case NBT_CONNECTING:
  1777. case NBT_RECONNECTING:
  1778. case NBT_SESSION_OUTBOUND:
  1779. case NBT_SESSION_WAITACCEPT:
  1780. case NBT_SESSION_INBOUND:
  1781. // do abortive disconnects when the session is not up yet
  1782. // to be sure the disconnect completes the client's irp.
  1783. Flags = TDI_DISCONNECT_ABORT;
  1784. case NBT_SESSION_UP:
  1785. //
  1786. // Call NbtDisconnect incase the connection has not disconnected yet
  1787. //
  1788. Request.Handle.ConnectionContext = (PVOID)pConnEle;
  1789. status = NbtDisconnect(&Request, &DefaultDisconnectTimeout, Flags, NULL, NULL, NULL);
  1790. //
  1791. // NOTE: there is no BREAK here... the next case MUST be executed too.
  1792. //
  1793. case NBT_ASSOCIATED:
  1794. case NBT_DISCONNECTING:
  1795. case NBT_DISCONNECTED:
  1796. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  1797. CHECK_PTR(pConnEle);
  1798. CTESpinLock(pConnEle,OldIrq);
  1799. RemoveEntryList(&pConnEle->Linkage);
  1800. InitializeListHead(&pConnEle->Linkage);
  1801. SET_STATE_UPPER (pConnEle, NBT_IDLE);
  1802. pConnEle->DiscFlag = 0;
  1803. //
  1804. // remove the connection from the client and put back on the
  1805. // unassociated list
  1806. //
  1807. if (pClientEle = pConnEle->pClientEle)
  1808. {
  1809. pConnEle->pClientEle = NULL;
  1810. CTESpinFree(pConnEle,OldIrq);
  1811. CTESpinLock(pClientEle,OldIrq1);
  1812. CTESpinLock(pConnEle,OldIrq);
  1813. InitializeListHead (&TempList);
  1814. pHead = &pClientEle->ListenHead;
  1815. pEntry = pHead->Flink;
  1816. while (pEntry != pHead)
  1817. {
  1818. pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
  1819. pEntry = pEntry->Flink; // Don't reference freed memory
  1820. if (pListen->pConnectEle == pConnEle)
  1821. {
  1822. RemoveEntryList(&pListen->Linkage);
  1823. InsertTailList (&TempList, &pListen->Linkage);
  1824. }
  1825. }
  1826. pDeviceContext = pClientEle->pDeviceContext;
  1827. CTESpinFree(pConnEle,OldIrq);
  1828. CTESpinFree(pClientEle,OldIrq1);
  1829. //
  1830. // Ensure that the connection has not been cleaned up in this interval
  1831. // Bug# 237836
  1832. //
  1833. if (pConnEle->Verify == NBT_VERIFY_CONNECTION)
  1834. {
  1835. ExInterlockedInsertTailList(&pDeviceContext->UpConnectionInUse,
  1836. &pConnEle->Linkage,
  1837. &pDeviceContext->LockInfo.SpinLock);
  1838. }
  1839. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  1840. while ((pEntry = TempList.Flink) != &TempList)
  1841. {
  1842. pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
  1843. RemoveEntryList(&pListen->Linkage);
  1844. CTEIoComplete (pListen->pIrp, STATUS_CANCELLED, 0);
  1845. CTEMemFree((PVOID)pListen);
  1846. }
  1847. }
  1848. else
  1849. {
  1850. CTESpinFree(pConnEle,OldIrq);
  1851. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  1852. }
  1853. break;
  1854. default:
  1855. break;
  1856. }
  1857. return(STATUS_SUCCESS);
  1858. }
  1859. //----------------------------------------------------------------------------
  1860. NTSTATUS
  1861. NbtCloseAddress(
  1862. IN TDI_REQUEST *pRequest,
  1863. OUT TDI_REQUEST_STATUS *pRequestStatus,
  1864. IN tDEVICECONTEXT *pContext,
  1865. IN PVOID pIrp)
  1866. /*++
  1867. Routine Description
  1868. This routine closes an address object for the client. Any connections
  1869. associated with the address object are immediately aborted and any requests
  1870. pending on the connection associated with the address object are
  1871. immediately completed with an appropriate error code. Any event handlers
  1872. that are registered are immediately deregistered and will not be called
  1873. after this request completes.
  1874. Note the the client actually passes a handle to the client object which is
  1875. chained off the address object. It is the client object that is closed,
  1876. which represents this clients attachment to the address object. Other
  1877. clients can continue to use the address object.
  1878. Arguments:
  1879. pRequest->Handle.AddressHandle - ptr to the ClientEle object.
  1880. pRequestStatus - return status for asynchronous completions.
  1881. pContext - the NBT device that this address is valid upon
  1882. pIrp - ptr to track for NT compatibility.
  1883. Return Values:
  1884. TDI_STATUS - status of the request
  1885. --*/
  1886. {
  1887. tCLIENTELE *pClientEle;
  1888. NTSTATUS status;
  1889. #ifndef VXD
  1890. UCHAR IrpFlags;
  1891. PIO_STACK_LOCATION pIrpsp;
  1892. #endif
  1893. CTEPagedCode();
  1894. pClientEle = (tCLIENTELE *)pRequest->Handle.ConnectionContext;
  1895. if (!pClientEle->pAddress)
  1896. {
  1897. // the address has already been deleted.
  1898. return(STATUS_SUCCESS);
  1899. }
  1900. IF_DBG(NBT_DEBUG_DISCONNECT)
  1901. KdPrint(("Nbt.NbtCloseAddress: Close Address Hit %16.16s<%X> %X\n",
  1902. pClientEle->pAddress->pNameAddr->Name,
  1903. pClientEle->pAddress->pNameAddr->Name[15],pClientEle));
  1904. NbtTrace(NBT_TRACE_NAMESRV, ("close address ClientEle=%p %!NBTNAME!<%02x>", pClientEle,
  1905. pClientEle->pAddress->pNameAddr->Name,
  1906. (unsigned)pClientEle->pAddress->pNameAddr->Name[15]));
  1907. #ifdef VXD
  1908. CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
  1909. //
  1910. // In NT-Land, closing connections is a two stage affair. However in
  1911. // the Vxd-Land, it is just a close, so call the other cleanup function
  1912. // here to do most of the work. In the NT implementation it is called
  1913. // from Ntisol.c, NTCleanupAddress.
  1914. //
  1915. pClientEle->pIrp = pIrp ;
  1916. status = NbtCleanUpAddress(pClientEle,pClientEle->pDeviceContext);
  1917. #else
  1918. // Note the special verifier that is set during the cleanup phase.
  1919. CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT_DOWN,tCLIENTELE,&status);
  1920. //
  1921. // clear the context value in the FileObject so that the client cannot
  1922. // pass this to us again
  1923. //
  1924. (VOID)NTClearFileObjectContext(pIrp);
  1925. pClientEle->pIrp = pIrp;
  1926. pIrpsp = IoGetCurrentIrpStackLocation(((PIRP)pIrp));
  1927. IrpFlags = pIrpsp->Control;
  1928. IoMarkIrpPending(((PIRP)pIrp));
  1929. #endif
  1930. NBT_DEREFERENCE_CLIENT(pClientEle);
  1931. return(STATUS_PENDING);
  1932. }
  1933. //----------------------------------------------------------------------------
  1934. NTSTATUS
  1935. NbtCleanUpAddress(
  1936. IN tCLIENTELE *pClientEle,
  1937. IN tDEVICECONTEXT *pDeviceContext
  1938. )
  1939. /*++
  1940. Routine Description:
  1941. This Routine handles the first stage of releasing an address object.
  1942. Arguments:
  1943. pIrp - a ptr to an IRP
  1944. Return Value:
  1945. NTSTATUS - status of the request
  1946. --*/
  1947. {
  1948. NTSTATUS status;
  1949. tLOWERCONNECTION *pLowerConn;
  1950. tCONNECTELE *pConnEle;
  1951. tCONNECTELE *pConnEleToDeref = NULL;
  1952. CTELockHandle OldIrq;
  1953. CTELockHandle OldIrq1;
  1954. CTELockHandle OldIrq2;
  1955. CTELockHandle OldIrq3;
  1956. PLIST_ENTRY pHead,pEntry;
  1957. PLIST_ENTRY pEntryConn;
  1958. tADDRESSELE *pAddress;
  1959. DWORD i;
  1960. LIST_ENTRY TempList;
  1961. // to prevent connections and datagram from the wire...remove from the
  1962. // list of clients hooked to the address element
  1963. //
  1964. pAddress = pClientEle->pAddress;
  1965. if (!pAddress)
  1966. {
  1967. // the address has already been deleted.
  1968. return(STATUS_SUCCESS);
  1969. }
  1970. // lock the address to coordinate with receiving datagrams - to avoid
  1971. // allowing the client to free datagram receive buffers in the middle
  1972. // of DgramHndlrNotOs finding a buffer
  1973. //
  1974. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1975. if (!IsListEmpty(&pClientEle->RcvDgramHead))
  1976. {
  1977. PLIST_ENTRY pHead;
  1978. PLIST_ENTRY pEntry;
  1979. tRCVELE *pRcvEle;
  1980. PCTE_IRP pRcvIrp;
  1981. pHead = &pClientEle->RcvDgramHead;
  1982. pEntry = pHead->Flink;
  1983. // prevent any datagram from the wire seeing this list
  1984. //
  1985. InitializeListHead(&pClientEle->RcvDgramHead);
  1986. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1987. while (pEntry != pHead)
  1988. {
  1989. pRcvEle = CONTAINING_RECORD(pEntry,tRCVELE,Linkage);
  1990. pRcvIrp = pRcvEle->pIrp;
  1991. CTEIoComplete(pRcvIrp,STATUS_NETWORK_NAME_DELETED,0);
  1992. pEntry = pEntry->Flink;
  1993. CTEMemFree(pRcvEle);
  1994. }
  1995. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1996. }
  1997. // lock the client and the device context till we're done
  1998. CTESpinLock(pClientEle,OldIrq2);
  1999. #ifndef VXD
  2000. //
  2001. // set to prevent reception of datagrams
  2002. // (Vxd doesn't use this handler)
  2003. //
  2004. pClientEle->evRcvDgram = TdiDefaultRcvDatagramHandler;
  2005. #endif
  2006. // so no one else can access the client element, set state to down. Therefore
  2007. // the verify checks will fail anywhere the client is accessed in the code,
  2008. // except in the NbtCloseAddress code which checks for this verifier value.
  2009. //
  2010. pClientEle->Verify = NBT_VERIFY_CLIENT_DOWN;
  2011. //
  2012. // Disassociate all Connections from this address object, first starting
  2013. // with any active connections, then followup with any idle connections.
  2014. //
  2015. pDeviceContext = pClientEle->pDeviceContext;
  2016. while ( !IsListEmpty( &pClientEle->ConnectActive ))
  2017. {
  2018. pEntry = RemoveHeadList( &pClientEle->ConnectActive ) ;
  2019. InitializeListHead(pEntry);
  2020. pConnEle = CONTAINING_RECORD( pEntry, tCONNECTELE, Linkage ) ;
  2021. CTESpinLock(pConnEle,OldIrq3);
  2022. NBT_REFERENCE_CONNECTION(pConnEle, REF_CONN_CLEANUP_ADDR); // Ensure conn stays around releasing lock below
  2023. CTESpinFree(pConnEle,OldIrq3);
  2024. CTESpinFree(pClientEle,OldIrq2);
  2025. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2026. //
  2027. // if we had a connection in partial rcv state, make sure to remove it from
  2028. // the list
  2029. //
  2030. #ifdef VXD
  2031. pLowerConn = pConnEle->pLowerConnId;
  2032. if ( pLowerConn->StateRcv == PARTIAL_RCV &&
  2033. (pLowerConn->fOnPartialRcvList == TRUE) )
  2034. {
  2035. RemoveEntryList( &pLowerConn->PartialRcvList ) ;
  2036. pLowerConn->fOnPartialRcvList = FALSE;
  2037. InitializeListHead(&pLowerConn->PartialRcvList);
  2038. }
  2039. #endif
  2040. //
  2041. // Deref any connections referenced earlier if necessary
  2042. //
  2043. if (pConnEleToDeref)
  2044. {
  2045. NBT_DEREFERENCE_CONNECTION(pConnEleToDeref, REF_CONN_CLEANUP_ADDR);
  2046. }
  2047. pConnEleToDeref = pConnEle;
  2048. status = NbtCleanUpConnection(pConnEle,pDeviceContext);
  2049. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2050. CTESpinLock(pClientEle,OldIrq2);
  2051. CTESpinLock(pConnEle,OldIrq3);
  2052. //
  2053. // remove from this list again incase SessionSetupContinue has put it
  2054. // back on the list - if no one has put it back on this list this
  2055. // call is a no op since we initialized the list head above
  2056. //
  2057. RemoveEntryList(&pConnEle->Linkage);
  2058. InitializeListHead (&pConnEle->Linkage);
  2059. CHECK_PTR(pConnEle);
  2060. SET_STATE_UPPER (pConnEle, NBT_IDLE);
  2061. pConnEle->pClientEle = NULL;
  2062. CTESpinFree(pConnEle,OldIrq3);
  2063. CTESpinFree(pClientEle,OldIrq2);
  2064. PUSH_LOCATION(0x80);
  2065. //
  2066. // put on the idle connection list, to wait for a close connection
  2067. // to come down.
  2068. // Bug # 405699
  2069. // Do this only if the NTCleanupConnection did not run in the interim.
  2070. //
  2071. ASSERT(pConnEle->RefCount >= 1);
  2072. if (!pConnEle->ConnectionCleanedUp)
  2073. {
  2074. ExInterlockedInsertTailList (&pDeviceContext->UpConnectionInUse,
  2075. &pConnEle->Linkage,
  2076. &pDeviceContext->LockInfo.SpinLock);
  2077. }
  2078. CTESpinLock(pClientEle,OldIrq2);
  2079. }
  2080. CTESpinFree(pClientEle,OldIrq2);
  2081. CTESpinLock(pDeviceContext,OldIrq1);
  2082. CTESpinLock(pClientEle,OldIrq2);
  2083. // We are now holding the JointLock + DeviceLock + ClientLock
  2084. //
  2085. // each idle connection creates a lower connection to the transport for
  2086. // inbound calls, therefore close a transport connection for each
  2087. // connection in this list and then "dissassociate" the connection from
  2088. // the address.
  2089. //
  2090. // make the list look empty so no connections will be serviced inbound
  2091. // from the wire
  2092. //
  2093. while (!IsListEmpty(&pClientEle->ConnectHead))
  2094. {
  2095. pEntry = pClientEle->ConnectHead.Flink;
  2096. RemoveEntryList (pEntry);
  2097. pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
  2098. CHECK_PTR(pConnEle);
  2099. ASSERT ((pConnEle->Verify==NBT_VERIFY_CONNECTION) || (pConnEle->Verify==NBT_VERIFY_CONNECTION_DOWN));
  2100. CTESpinLock(pConnEle,OldIrq3);
  2101. //
  2102. // The Connection Element could be currently being cleaned up in NbtCleanUpConnection, so verify
  2103. //
  2104. if (pConnEle->Verify != NBT_VERIFY_CONNECTION)
  2105. {
  2106. InitializeListHead (&pConnEle->Linkage);
  2107. CTESpinFree(pConnEle,OldIrq3);
  2108. continue;
  2109. }
  2110. InsertTailList(&pDeviceContext->UpConnectionInUse,&pConnEle->Linkage);
  2111. //
  2112. // Cannot enable the following ASSERT. When NetBT deregister the address,
  2113. // RDR will immediately close all its connections. However, the connections
  2114. // could be residing in the system work item list, which can have a
  2115. // refcount 4 (there could be more, but we haven't seen).
  2116. //
  2117. // ASSERT(pConnEle->RefCount == 1 || pConnEle->RefCount == 2);
  2118. //
  2119. SET_STATE_UPPER (pConnEle, NBT_IDLE);
  2120. pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
  2121. pConnEle->pClientEle = NULL;
  2122. CTESpinFree(pConnEle,OldIrq3);
  2123. //
  2124. // Get a free connection to the transport and close it
  2125. // for each free connection on this list. It is possible that this
  2126. // free list could be empty if an inbound connection was occurring
  2127. // right at this moment. In which case we would leave an extra connection
  2128. // object to the transport lying around... not a problem.
  2129. if (!IsListEmpty(&pDeviceContext->LowerConnFreeHead))
  2130. {
  2131. pEntryConn = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
  2132. pLowerConn = CONTAINING_RECORD(pEntryConn,tLOWERCONNECTION,Linkage);
  2133. InterlockedDecrement (&pDeviceContext->NumFreeLowerConnections);
  2134. IF_DBG(NBT_DEBUG_DISCONNECT)
  2135. KdPrint(("Nbt.NbtCleanUpAddress: Closing Handle %p->%X\n",pLowerConn,pLowerConn->FileHandle));
  2136. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, TRUE);
  2137. }
  2138. }
  2139. // check for any datagrams still outstanding. These could be waiting on
  2140. // name queries to complete, so there could be timers associated with them
  2141. //
  2142. // Complete any outstanding listens not on an active connection
  2143. //
  2144. //
  2145. // make the list look empty so no connections will be serviced inbound
  2146. // from the wire
  2147. //
  2148. //
  2149. // Move all of the Listen requests onto a temporary list
  2150. //
  2151. InitializeListHead (&TempList);
  2152. while (!IsListEmpty(&pClientEle->ListenHead))
  2153. {
  2154. pEntry = pClientEle->ListenHead.Flink;
  2155. RemoveEntryList (pEntry);
  2156. InsertTailList (&TempList, pEntry);
  2157. }
  2158. CTESpinFree(pClientEle, OldIrq2);
  2159. CTESpinFree(pDeviceContext,OldIrq1);
  2160. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2161. while ((pEntry = TempList.Flink) != &TempList)
  2162. {
  2163. tLISTENREQUESTS * pListen ;
  2164. pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
  2165. RemoveEntryList(&pListen->Linkage);
  2166. CTEIoComplete( pListen->pIrp, STATUS_NETWORK_NAME_DELETED, 0);
  2167. CTEMemFree( pListen );
  2168. }
  2169. //
  2170. // Deref any connections referenced earlier if necessary
  2171. //
  2172. if (pConnEleToDeref)
  2173. {
  2174. NBT_DEREFERENCE_CONNECTION(pConnEleToDeref, REF_CONN_CLEANUP_ADDR);
  2175. }
  2176. #ifdef VXD
  2177. //
  2178. // Complete any outstanding ReceiveAnys on this client element
  2179. //
  2180. DbgPrint("NbtCleanupAddress: Completing all RcvAny NCBs\r\n") ;
  2181. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2182. CTESpinLock(pClientEle,OldIrq2);
  2183. pHead = &pClientEle->RcvAnyHead;
  2184. pEntry = pHead->Flink;
  2185. //
  2186. // make the list look empty so no connections will be serviced inbound
  2187. // from the wire
  2188. //
  2189. InitializeListHead(pHead);
  2190. CTESpinFree(pClientEle, OldIrq2);
  2191. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2192. while (pEntry != pHead )
  2193. {
  2194. PRCV_CONTEXT pRcvContext ;
  2195. pRcvContext = CONTAINING_RECORD(pEntry,RCV_CONTEXT,ListEntry);
  2196. pEntry = pEntry->Flink;
  2197. CTEIoComplete( pRcvContext->pNCB, STATUS_NETWORK_NAME_DELETED, TRUE );
  2198. FreeRcvContext( pRcvContext );
  2199. }
  2200. #endif
  2201. // *TODO the code above only removes names that are being resolved, and
  2202. // leaves any datagram sends that are currently active with the
  2203. // transport... these should be cancelled too by cancelling the irp..
  2204. // Put this code in when the Irp cancelling code is done.
  2205. return(STATUS_SUCCESS);
  2206. }
  2207. //----------------------------------------------------------------------------
  2208. NTSTATUS
  2209. NbtCloseConnection(
  2210. IN TDI_REQUEST *pRequest,
  2211. OUT TDI_REQUEST_STATUS *pRequestStatus,
  2212. IN tDEVICECONTEXT *pDeviceContext,
  2213. IN PVOID pIrp)
  2214. /*++
  2215. Routine Description
  2216. This routine closes a connection object for the client. Closing is
  2217. different than disconnecting. A disconnect breaks a connection with a
  2218. peer whereas the close removes this connection endpoint from the local
  2219. NBT only. NtClose causes NTCleanup to be called first which does the
  2220. session close. This routine then does frees memory associated with the
  2221. connection elements.
  2222. Arguments:
  2223. Return Values:
  2224. TDI_STATUS - status of the request
  2225. --*/
  2226. {
  2227. tCONNECTELE *pConnEle;
  2228. NTSTATUS status;
  2229. CTEPagedCode();
  2230. pConnEle = pRequest->Handle.ConnectionContext;
  2231. IF_DBG(NBT_DEBUG_DISCONNECT)
  2232. KdPrint(("Nbt.NbtCloseConnection: Hit!! state = %X pConnEle %X\n",pConnEle->state,pConnEle));
  2233. #ifndef VXD
  2234. CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION_DOWN,tCONNECTELE,&status);
  2235. IoMarkIrpPending((PIRP)pIrp); // Bug 261575: to make driver verifier happy
  2236. #else
  2237. CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
  2238. //
  2239. // Call the Cleanup function, which NT calls from ntisol, NtCleanupConnection
  2240. //
  2241. status = NbtCleanUpConnection(pConnEle,pDeviceContext );
  2242. #endif
  2243. // NOTE:
  2244. // the NBtDereference routine will complete the irp and return pending
  2245. //
  2246. NbtTrace(NBT_TRACE_DISCONNECT, ("Close connection Irp=%p Upper=%p Lower=%p Client=%p Device=%p",
  2247. pIrp, pConnEle, pConnEle->pLowerConnId, pConnEle->pClientEle, pConnEle->pDeviceContext));
  2248. pConnEle->pIrpClose = pIrp;
  2249. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CREATE);
  2250. return (STATUS_PENDING);
  2251. }
  2252. //----------------------------------------------------------------------------
  2253. NTSTATUS
  2254. NbtCleanUpConnection(
  2255. IN tCONNECTELE *pConnEle,
  2256. IN tDEVICECONTEXT *pDeviceContext
  2257. )
  2258. /*++
  2259. Routine Description:
  2260. This Routine handles running down a connection in preparation for a close
  2261. that will come in next. NtClose hits this entry first, and then it hits
  2262. the NTCloseConnection next. If the connection was outbound, then the
  2263. address object must be closed as well as the connection. This routine
  2264. mainly deals with the pLowerconn connection to the transport whereas
  2265. NbtCloseConnection deals with closing pConnEle, the connection to the client.
  2266. If DisassociateConnection is called by the client then it will do most of
  2267. this cleanup.
  2268. Arguments:
  2269. Return Value:
  2270. NTSTATUS - status of the request
  2271. --*/
  2272. {
  2273. NTSTATUS status = STATUS_SUCCESS;
  2274. NTSTATUS Locstatus;
  2275. CTELockHandle OldIrq;
  2276. CTELockHandle OldIrq1;
  2277. CTELockHandle OldIrq2;
  2278. tLOWERCONNECTION *pLowerConn;
  2279. PLIST_ENTRY pEntry;
  2280. BOOLEAN Originator = TRUE;
  2281. ULONG LowerState = NBT_IDLE;
  2282. TDI_REQUEST Request;
  2283. tLISTENREQUESTS *pListen;
  2284. tCLIENTELE *pClientEle;
  2285. PLIST_ENTRY pHead;
  2286. LIST_ENTRY TempList;
  2287. BOOLEAN QueueCleanupBool=FALSE;
  2288. BOOLEAN DoDisconnect=TRUE;
  2289. BOOLEAN FreeLower;
  2290. NbtTrace(NBT_TRACE_DISCONNECT, ("Cleanup connection Upper=%p Lower=%p Client=%p Device=%p",
  2291. pConnEle, pConnEle->pLowerConnId, pConnEle->pClientEle, pConnEle->pDeviceContext));
  2292. //
  2293. // save the lower connection origination flag for later
  2294. //
  2295. pLowerConn = pConnEle->pLowerConnId;
  2296. if (pLowerConn)
  2297. {
  2298. Originator = pLowerConn->bOriginator;
  2299. }
  2300. // the connection has not been associated so there is no further work to
  2301. // do here.
  2302. //
  2303. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  2304. //
  2305. // If the state is NBT_IDLE, the connection has already been disassociated,
  2306. // and the next action will be a close, so change the verifier to allow
  2307. // the close to complete
  2308. //
  2309. if (pConnEle->state != NBT_IDLE)
  2310. {
  2311. BOOLEAN DoCleanup = FALSE;
  2312. CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
  2313. //
  2314. // check if there is an outstanding name query going on and if so
  2315. // then cancel the timer and call the completion routine.
  2316. //
  2317. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  2318. CTESpinLock(pConnEle,OldIrq);
  2319. if ((pConnEle->state == NBT_CONNECTING) ||
  2320. (pConnEle->state == NBT_RECONNECTING))
  2321. {
  2322. status = CleanupConnectingState(pConnEle,pDeviceContext,&OldIrq,&OldIrq2);
  2323. //
  2324. // Pending means that the connection is currently being setup
  2325. // by TCP, so do a disconnect, below.
  2326. //
  2327. if (status != STATUS_PENDING)
  2328. {
  2329. //
  2330. // Since the connection is not setup with the transport yet
  2331. // there is no need to call nbtdisconnect
  2332. //
  2333. DoDisconnect = FALSE;
  2334. }
  2335. }
  2336. //
  2337. // all other states of the connection are handled by NbtDisconnect
  2338. // which will send a disconnect down the to transport and then
  2339. // cleanup things.
  2340. //
  2341. CTESpinFree(pConnEle,OldIrq);
  2342. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2343. CTEExReleaseResource(&NbtConfig.Resource);
  2344. Request.Handle.ConnectionContext = (PVOID)pConnEle;
  2345. if (DoDisconnect)
  2346. {
  2347. NbtTrace(NBT_TRACE_DISCONNECT, ("Abort connection ==> ConnEle %p", pConnEle));
  2348. status = NbtDisconnect(
  2349. &Request,
  2350. &DefaultDisconnectTimeout,
  2351. TDI_DISCONNECT_ABORT,
  2352. NULL,
  2353. NULL,
  2354. NULL
  2355. );
  2356. NbtTrace(NBT_TRACE_DISCONNECT, ("NbtDisconnect returns %!status!", status));
  2357. ASSERT (STATUS_PENDING != status);
  2358. }
  2359. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  2360. // we don't want to return Invalid connection if we disconnect an
  2361. // already disconnected connection.
  2362. if (status == STATUS_CONNECTION_INVALID)
  2363. {
  2364. status = STATUS_SUCCESS;
  2365. }
  2366. }
  2367. CTESpinLock(pConnEle,OldIrq);
  2368. //
  2369. // if the verify value is already set to connection down then we have
  2370. // been through here already and do not want to free a lower connection.
  2371. // i.e. when the client calls close address then calls close connection.
  2372. //
  2373. if (pConnEle->Verify == NBT_VERIFY_CONNECTION)
  2374. {
  2375. FreeLower = TRUE;
  2376. }
  2377. else
  2378. {
  2379. FreeLower = FALSE;
  2380. }
  2381. pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
  2382. //
  2383. // Free any posted Rcv buffers that have not been filled
  2384. //
  2385. FreeRcvBuffers(pConnEle,&OldIrq);
  2386. // check if any listens have been setup for this connection, and
  2387. // remove them if so
  2388. //
  2389. pClientEle = pConnEle->pClientEle;
  2390. CTESpinFree(pConnEle,OldIrq);
  2391. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2392. CTESpinLock(pDeviceContext,OldIrq1);
  2393. InitializeListHead (&TempList);
  2394. if (pClientEle)
  2395. {
  2396. CTESpinLock(pClientEle,OldIrq2);
  2397. pHead = &pClientEle->ListenHead;
  2398. pEntry = pHead->Flink;
  2399. while (pEntry != pHead)
  2400. {
  2401. pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
  2402. pEntry = pEntry->Flink; // Don't reference freed memory
  2403. if (pListen->pConnectEle == pConnEle)
  2404. {
  2405. RemoveEntryList(&pListen->Linkage);
  2406. InsertTailList(&TempList, &pListen->Linkage);
  2407. }
  2408. }
  2409. CTESpinFree(pClientEle,OldIrq2);
  2410. }
  2411. CTESpinLock(pConnEle,OldIrq2);
  2412. //
  2413. // Unlink the connection element from the client's list or the device context
  2414. // if its not associated yet.
  2415. //
  2416. CHECK_PTR(pConnEle);
  2417. if (pConnEle->state > NBT_IDLE)
  2418. {
  2419. // do the disassociate here
  2420. //
  2421. SET_STATE_UPPER (pConnEle, NBT_IDLE);
  2422. pConnEle->pClientEle = NULL;
  2423. }
  2424. RemoveEntryList(&pConnEle->Linkage);
  2425. InitializeListHead(&pConnEle->Linkage);
  2426. CTESpinFree(pConnEle,OldIrq2);
  2427. CTESpinFree(pDeviceContext,OldIrq1);
  2428. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2429. CTEExReleaseResource(&NbtConfig.Resource);
  2430. while ((pEntry = TempList.Flink) != &TempList)
  2431. {
  2432. pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
  2433. RemoveEntryList(&pListen->Linkage);
  2434. CTEIoComplete (pListen->pIrp, STATUS_CANCELLED, 0);
  2435. CTEMemFree (pListen);
  2436. }
  2437. // this could be status pending from NbtDisconnect...
  2438. //
  2439. return(status);
  2440. }
  2441. //----------------------------------------------------------------------------
  2442. extern
  2443. VOID
  2444. FreeRcvBuffers(
  2445. tCONNECTELE *pConnEle,
  2446. CTELockHandle *pOldIrq
  2447. )
  2448. /*++
  2449. Routine Description:
  2450. This Routine handles freeing any recv buffers posted by the client.
  2451. The pConnEle lock could be held prior to calling this routine.
  2452. Arguments:
  2453. pListHead
  2454. pTracker
  2455. Return Value:
  2456. NTSTATUS - status of the request
  2457. --*/
  2458. {
  2459. NTSTATUS status = STATUS_SUCCESS;
  2460. PLIST_ENTRY pHead;
  2461. pHead = &pConnEle->RcvHead;
  2462. while (!IsListEmpty(pHead))
  2463. {
  2464. PLIST_ENTRY pRcvEntry;
  2465. PVOID pRcvElement ;
  2466. KdPrint(("Nbt.FreeRcvBuffers: ***Freeing Posted Rcvs on Connection Cleanup!\n"));
  2467. pRcvEntry = RemoveHeadList(pHead);
  2468. CTESpinFree(pConnEle,*pOldIrq);
  2469. #ifndef VXD
  2470. pRcvElement = CONTAINING_RECORD(pRcvEntry,IRP,Tail.Overlay.ListEntry);
  2471. CTEIoComplete( (PIRP) pRcvElement, STATUS_CANCELLED,0);
  2472. #else
  2473. pRcvElement = CONTAINING_RECORD(pRcvEntry, RCV_CONTEXT, ListEntry ) ;
  2474. CTEIoComplete( ((PRCV_CONTEXT)pRcvEntry)->pNCB, STATUS_CANCELLED, 0);
  2475. #endif
  2476. CTESpinLock(pConnEle,*pOldIrq);
  2477. }
  2478. }
  2479. //----------------------------------------------------------------------------
  2480. NTSTATUS
  2481. FindPendingRequest(
  2482. IN tLMHSVC_REQUESTS *pLmHRequests,
  2483. IN tDGRAM_SEND_TRACKING *pTracker,
  2484. OUT NBT_WORK_ITEM_CONTEXT **pContextRet
  2485. )
  2486. {
  2487. PLIST_ENTRY pEntry;
  2488. NBT_WORK_ITEM_CONTEXT *pWiContext = NULL;
  2489. pWiContext = (NBT_WORK_ITEM_CONTEXT *) pLmHRequests->Context;
  2490. if (pWiContext && (pWiContext->pTracker == pTracker))
  2491. {
  2492. pLmHRequests->Context = NULL;
  2493. NTClearContextCancel (pWiContext);
  2494. *pContextRet = pWiContext;
  2495. return(STATUS_SUCCESS);
  2496. }
  2497. else
  2498. {
  2499. //
  2500. // check the list for this tracker
  2501. //
  2502. pEntry = pLmHRequests->ToResolve.Flink;
  2503. while (pEntry != &pLmHRequests->ToResolve)
  2504. {
  2505. pWiContext = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Linkage);
  2506. pEntry = pEntry->Flink;
  2507. if (pTracker == pWiContext->pTracker)
  2508. {
  2509. RemoveEntryList(pEntry);
  2510. *pContextRet = pWiContext;
  2511. return(STATUS_SUCCESS);
  2512. }
  2513. }
  2514. }
  2515. return (STATUS_UNSUCCESSFUL);
  2516. }
  2517. //----------------------------------------------------------------------------
  2518. NTSTATUS
  2519. CleanupConnectingState(
  2520. IN tCONNECTELE *pConnEle,
  2521. IN tDEVICECONTEXT *pDeviceContext,
  2522. IN CTELockHandle *OldIrq, // pConnEle lock
  2523. IN CTELockHandle *OldIrq2 // joint lock
  2524. )
  2525. /*++
  2526. Routine Description:
  2527. This Routine handles running down a connection in the NBT_CONNECTING
  2528. state since that connection could be doing a number of things such as:
  2529. 1) Broadcast or WINS name Query
  2530. 2) LmHosts name query
  2531. 3) DNS name query
  2532. 4) Tcp Connection setup
  2533. The JointLock and the pConnEle lock are held when calling this routine.
  2534. Arguments:
  2535. pConnEle - ptr to the connection
  2536. pDeviceContext - the device context
  2537. Return Value:
  2538. NTSTATUS - status of the request
  2539. --*/
  2540. {
  2541. NTSTATUS status = STATUS_UNSUCCESSFUL;
  2542. tDGRAM_SEND_TRACKING *pTrackerName = NULL;
  2543. tDGRAM_SEND_TRACKING *pTrackerConnect = NULL;
  2544. tNAMEADDR *pNameAddr = NULL;
  2545. NBT_WORK_ITEM_CONTEXT *pWiContext = NULL;
  2546. tLOWERCONNECTION *pLowerConn;
  2547. COMPLETIONCLIENT pClientCompletion;
  2548. PVOID Context;
  2549. NTSTATUS Locstatus;
  2550. //
  2551. // save the lower connection origination flag for later
  2552. //
  2553. pLowerConn = pConnEle->pLowerConnId;
  2554. pTrackerConnect = (tDGRAM_SEND_TRACKING *) pConnEle->pIrpRcv;
  2555. //CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&Locstatus);
  2556. if (pConnEle->state == NBT_CONNECTING)
  2557. {
  2558. if ((pLowerConn) && // The LowerConnection could have gone away if it was deleted
  2559. (pLowerConn->State == NBT_CONNECTING))
  2560. {
  2561. LOCATION(0x6E)
  2562. //
  2563. // We are setting up the TCP connection to the transport Now
  2564. // so it is safe to call NbtDisconnect on this connection and
  2565. // let that cleanup the mess - use this retcode to signify that.
  2566. //
  2567. return(STATUS_PENDING);
  2568. }
  2569. //
  2570. // check if the name query is held up in doing a LmHost or DNS
  2571. // Name Query
  2572. //
  2573. // check if there is an outstanding name query going on and if so
  2574. // then cancel the timer and call the completion routine.
  2575. //
  2576. IF_DBG(NBT_DEBUG_DISCONNECT)
  2577. KdPrint(("Nbt.CleanupConnectingState: Cleanup in the Connecting State %X\n",pConnEle));
  2578. pTrackerName = pTrackerConnect->pTrackerWorker; // QueryNameOnNet tracker
  2579. if (NBT_VERIFY_HANDLE (pTrackerName, NBT_VERIFY_TRACKER) && pTrackerConnect->pDestName)
  2580. {
  2581. status = FindInHashTable(NbtConfig.pRemoteHashTbl,
  2582. pTrackerConnect->pDestName,
  2583. NbtConfig.pScope,
  2584. &pNameAddr);
  2585. //
  2586. // if there is a timer, then the connection setup is still
  2587. // waiting on the name query. If no timer, then we could be
  2588. // waiting on an LmHosts or DNS name query or we
  2589. // are waiting on the TCP connection setup - stopping the timer
  2590. // should cleanup the tracker.
  2591. //
  2592. if (NT_SUCCESS(status))
  2593. {
  2594. tTIMERQENTRY *pTimer;
  2595. CHECK_PTR(pNameAddr);
  2596. if (pNameAddr->NameTypeState & STATE_RESOLVED)
  2597. {
  2598. //
  2599. // the name has resolved, but not started setting up the
  2600. // session yet, so return this status to tell the caller
  2601. // to cancel the tracker.
  2602. //
  2603. return(STATUS_UNSUCCESSFUL);
  2604. }
  2605. else if (pTimer = pNameAddr->pTimer)
  2606. {
  2607. IF_DBG(NBT_DEBUG_NAMESRV)
  2608. KdPrint(("Nbt.CleanupConnectingState: Cleanup During NameQuery: pConnEle=%X\n",
  2609. pConnEle));
  2610. pNameAddr->pTimer = NULL;
  2611. status = StopTimer(pTimer,&pClientCompletion,&Context);
  2612. #ifdef DEAD_CODE
  2613. //
  2614. // remove the name from the hash table, since it did not resolve
  2615. //
  2616. pNameAddr->NameTypeState &= ~STATE_RESOLVING;
  2617. pNameAddr->NameTypeState |= STATE_RELEASED;
  2618. pNameAddr->pTracker = NULL;
  2619. if (pClientCompletion)
  2620. {
  2621. NBT_DEREFERENCE_NAMEADDR (pNameAddr, TRUE);
  2622. }
  2623. #endif // DEAD_CODE
  2624. pTrackerName = NULL; // since StopTimer should have cleaned up the tracker, null it out
  2625. }
  2626. else
  2627. {
  2628. //
  2629. // check if the name is waiting on an LmHost name Query
  2630. // or a DNS name query
  2631. //
  2632. status = FindPendingRequest (&LmHostQueries, pTrackerName, &pWiContext);
  2633. if (!NT_SUCCESS(status))
  2634. {
  2635. #ifndef VXD
  2636. status = FindPendingRequest (&DnsQueries, pTrackerName, &pWiContext);
  2637. if (!NT_SUCCESS(status))
  2638. {
  2639. status = FindPendingRequest (&CheckAddr, pTrackerName, &pWiContext);
  2640. }
  2641. #endif
  2642. }
  2643. if (NT_SUCCESS(status))
  2644. {
  2645. IF_DBG(NBT_DEBUG_NAMESRV)
  2646. KdPrint(("Nbt.CleanupConnectingState: Found pending NameQuery for pConnEle %X\n",
  2647. pConnEle));
  2648. }
  2649. }
  2650. }
  2651. // ...else....
  2652. // the completion routine has already run, so we are
  2653. // in the state of starting a Tcp Connection, so
  2654. // let nbtdisconnect handle it. (below).
  2655. //
  2656. }
  2657. } // connnecting state
  2658. else if (pConnEle->state == NBT_RECONNECTING)
  2659. {
  2660. LOCATION(0x77);
  2661. //
  2662. // this should signal NbtConnect not to do the reconnect
  2663. //
  2664. pTrackerConnect->pTrackerWorker->Flags = TRACKER_CANCELLED;
  2665. }
  2666. if (NT_SUCCESS(status))
  2667. {
  2668. // for items on the LmHost or Dns queues, get the completion routine
  2669. // out of the Work Item context first
  2670. //
  2671. if (pWiContext)
  2672. {
  2673. LOCATION(0x78);
  2674. pClientCompletion = pWiContext->ClientCompletion;
  2675. Context = pWiContext->pClientContext;
  2676. // for DNS and LmHosts, the tracker needs to be freed and the name
  2677. // removed from the hash table
  2678. //
  2679. if (pTrackerName)
  2680. {
  2681. LOCATION(0x79);
  2682. CTESpinFree(pConnEle,*OldIrq);
  2683. CTESpinFree(&NbtConfig.JointLock,*OldIrq2);
  2684. //
  2685. // remove the name from the hash table, since it did not resolve
  2686. //
  2687. SetNameState (pTrackerName->pNameAddr, NULL, FALSE);
  2688. NBT_DEREFERENCE_TRACKER(pTrackerName, FALSE);
  2689. CTESpinLock(&NbtConfig.JointLock,*OldIrq2);
  2690. CTESpinLock(pConnEle,*OldIrq);
  2691. }
  2692. CTEMemFree(pWiContext);
  2693. }
  2694. if (pClientCompletion)
  2695. {
  2696. LOCATION(0x7A);
  2697. CTESpinFree(pConnEle,*OldIrq);
  2698. CTESpinFree(&NbtConfig.JointLock,*OldIrq2);
  2699. //
  2700. // The completion routine is SessionSetupContinue
  2701. // and it will cleanup the lower connection and
  2702. // return the client's irp
  2703. //
  2704. status = STATUS_SUCCESS;
  2705. CompleteClientReq(pClientCompletion, Context,STATUS_CANCELLED);
  2706. CTESpinLock(&NbtConfig.JointLock,*OldIrq2);
  2707. CTESpinLock(pConnEle,*OldIrq);
  2708. }
  2709. else
  2710. {
  2711. status = STATUS_UNSUCCESSFUL;
  2712. }
  2713. }
  2714. return(status);
  2715. }
  2716. NTSTATUS
  2717. CheckConnect(
  2718. IN tCONNECTELE *pConnEle,
  2719. IN tCLIENTELE *pClientEle,
  2720. IN tDEVICECONTEXT *pDeviceContext
  2721. )
  2722. /*++
  2723. This function should be called with the following locks held.
  2724. NbtConfig.Resource
  2725. NbtConfig.JointLock SpinLock
  2726. pClientEle SpinLock
  2727. pConnEle SpinLock
  2728. --*/
  2729. {
  2730. /*
  2731. * The state can be NBT_DISCONNECTING if this ConnectionElement
  2732. * is being reused to setup a connection to a different Endpoint
  2733. */
  2734. if ((pConnEle->state != NBT_ASSOCIATED) &&
  2735. (pConnEle->state != NBT_DISCONNECTING) &&
  2736. (pConnEle->state != NBT_DISCONNECTED)) {
  2737. return STATUS_INVALID_DEVICE_REQUEST;
  2738. }
  2739. if (pClientEle->Verify != NBT_VERIFY_CLIENT ) {
  2740. return (pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN)? STATUS_CANCELLED: STATUS_INVALID_HANDLE;
  2741. }
  2742. /*
  2743. * be sure the name is in the correct state for a connection
  2744. */
  2745. if ((!IsDeviceNetbiosless(pDeviceContext)) &&
  2746. (pClientEle->pAddress->pNameAddr->NameTypeState & STATE_CONFLICT)) {
  2747. return STATUS_DUPLICATE_NAME;
  2748. }
  2749. /*
  2750. * this code handles the case when DHCP has not assigned an IP address yet
  2751. */
  2752. if (pDeviceContext->IpAddress == 0) {
  2753. return STATUS_BAD_NETWORK_PATH;
  2754. }
  2755. return STATUS_SUCCESS;
  2756. /*
  2757. //
  2758. // this code handles the case when DHCP has not assigned an IP address yet
  2759. //
  2760. ASSERT (pDeviceContext->IpAddress == 0 || !pDeviceContext->pSessionFileObject);
  2761. if (pDeviceContext->IpAddress == 0 || !pDeviceContext->pSessionFileObject) {
  2762. return STATUS_BAD_NETWORK_PATH;
  2763. }
  2764. return STATUS_SUCCESS;
  2765. */
  2766. }
  2767. NTSTATUS
  2768. NbtReConnect(
  2769. IN tDGRAM_SEND_TRACKING *pTracker,
  2770. IN tIPADDRESS DestIp
  2771. )
  2772. {
  2773. tCONNECTELE *pConnEle;
  2774. tCLIENTELE *pClientEle;
  2775. NTSTATUS status;
  2776. CTELockHandle OldIrq;
  2777. CTELockHandle OldIrq1;
  2778. CTELockHandle OldIrq2;
  2779. tIPADDRESS IpAddress;
  2780. tNAMEADDR *pNameAddr;
  2781. tLOWERCONNECTION *pLowerConn;
  2782. tDEVICECONTEXT *pDeviceContext;
  2783. #ifdef _PNP_POWER_
  2784. if (NbtConfig.Unloading) {
  2785. KdPrint (("Nbt.NbtReConnect: --> ERROR New Connect request while Unloading!!!\n"));
  2786. return STATUS_INSUFFICIENT_RESOURCES;
  2787. }
  2788. #endif // _PNP_POWER_
  2789. NbtTrace(NBT_TRACE_OUTBOUND, ("Reconnect to %!ipaddr! for pTracker %p", DestIp, pTracker));
  2790. /*
  2791. * Only NETBIOS name can hit requery or retarget
  2792. */
  2793. ASSERT(pTracker->RemoteNameLength <= NETBIOS_NAME_SIZE);
  2794. pConnEle = pTracker->pConnEle;
  2795. //
  2796. // Acquire this resource to co-ordinate with DHCP changing the IP
  2797. // address
  2798. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  2799. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  2800. if ((!(NBT_VERIFY_HANDLE (pConnEle, NBT_VERIFY_CONNECTION))) || (!(pClientEle = pConnEle->pClientEle))) {
  2801. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2802. CTEExReleaseResource(&NbtConfig.Resource);
  2803. return STATUS_INVALID_DEVICE_REQUEST;
  2804. }
  2805. CTESpinLock(pClientEle,OldIrq1);
  2806. CTESpinLock(pConnEle,OldIrq);
  2807. pDeviceContext = pClientEle->pDeviceContext;
  2808. ASSERT(!IsDeviceNetbiosless(pDeviceContext)); // NetbiosLess device cannot hit reconnect or retarget case
  2809. status = CheckConnect(pConnEle, pClientEle, pDeviceContext);
  2810. if (status != STATUS_SUCCESS) {
  2811. pConnEle->pIrp = NULL;
  2812. CTESpinFree(pConnEle,OldIrq);
  2813. CTESpinFree(pClientEle,OldIrq1);
  2814. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2815. CTEExReleaseResource(&NbtConfig.Resource);
  2816. NbtTrace(NBT_TRACE_OUTBOUND, ("CheckConnect returns %!status! for pTracker %p", status, pTracker));
  2817. return status;
  2818. }
  2819. //
  2820. // check if the Reconnect got cancelled
  2821. //
  2822. pTracker->pTrackerWorker = NULL;
  2823. if (pTracker->Flags & TRACKER_CANCELLED) {
  2824. NbtTrace(NBT_TRACE_OUTBOUND, ("Connection Request is cancelled for pTracker %p", pTracker));
  2825. //
  2826. // if SessionSetupContinue has run, it has set the refcount to zero
  2827. //
  2828. if (pTracker->RefConn == 0) {
  2829. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  2830. } else {
  2831. pTracker->RefConn--;
  2832. }
  2833. pConnEle->pIrp = NULL;
  2834. CTESpinFree(pConnEle,OldIrq);
  2835. CTESpinFree(pClientEle,OldIrq1);
  2836. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2837. CTEExReleaseResource(&NbtConfig.Resource);
  2838. return STATUS_CANCELLED;
  2839. }
  2840. SET_STATE_UPPER (pConnEle, NBT_CONNECTING);
  2841. // Increment the ref count so that a cleanup cannot remove
  2842. // the pConnEle till the session is setup - one of these is removed when
  2843. // the session is setup and the other is removed when it is disconnected.
  2844. //
  2845. NBT_REFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  2846. NBT_REFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  2847. ASSERT(pConnEle->RefCount >= 3);
  2848. //
  2849. // unlink the connection from the idle connection list and put on active list
  2850. //
  2851. RemoveEntryList(&pConnEle->Linkage);
  2852. InsertTailList(&pClientEle->ConnectActive,&pConnEle->Linkage);
  2853. // this field is used to hold a disconnect irp if it comes down during
  2854. // NBT_CONNECTING or NBT_SESSION_OUTBOUND states
  2855. //
  2856. pConnEle->pIrpDisc = NULL;
  2857. // if null then this is being called to reconnect and the tracker is already
  2858. // setup.
  2859. //
  2860. // for the reconnect case we must skip most of the processing since
  2861. // the tracker is all set up already. All we need to do is
  2862. // retry the connection.
  2863. pTracker->RefConn++;
  2864. pTracker->SendBuffer.pBuffer = pTracker->pRemoteName;
  2865. // store the tracker in the Irp Rcv ptr so it can be used by the
  2866. // session setup code in hndlrs.c in the event the destination is
  2867. // between posting listens and this code should re-attempt the
  2868. // session setup. The code in hndlrs.c returns the tracker to its
  2869. // free list and frees the session hdr memory too.
  2870. //
  2871. // We need to set this while holding the ConnEle lock because the client
  2872. // can call NbtDisconnect while we are opening a Tcp handle and try to
  2873. // set the Tracker's flag to TRACKER_CANCELLED
  2874. //
  2875. pConnEle->pIrpRcv = (PIRP)pTracker;
  2876. CTESpinFree(pConnEle,OldIrq);
  2877. CTESpinFree(pClientEle,OldIrq1);
  2878. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2879. // open a connection with the transport for this session
  2880. status = NbtOpenAndAssocConnection (pDeviceContext, pConnEle, &pConnEle->pLowerConnId, '3');
  2881. if (!NT_SUCCESS(status)) {
  2882. NbtTrace(NBT_TRACE_OUTBOUND, ("NbtOpenAndAssocConnection return %!status! for pTracker %p",
  2883. status, pTracker));
  2884. goto NbtConnect_Check;
  2885. }
  2886. // We need to track that this side originated the call so we discard this
  2887. // connection at the end
  2888. //
  2889. pConnEle->pLowerConnId->bOriginator = TRUE;
  2890. // set this state to associated so that the cancel irp routine
  2891. // can differentiate the name query stage from the setupconnection
  2892. // stage since pConnEle is in the Nbtconnecting state for both.
  2893. //
  2894. SET_STATE_LOWER (pConnEle->pLowerConnId, NBT_ASSOCIATED);
  2895. // if this routine is called to do a reconnect, DO NOT close another
  2896. // Lower Connection since one was closed the on the first
  2897. // connect attempt.
  2898. // the original "ToName" was stashed in this unused
  2899. // ptr! - for the Reconnect case
  2900. // the pNameAddr part of pTracker(pDestName) needs to pt. to
  2901. // the name so that SessionSetupContinue can find the name
  2902. pTracker->pDestName = pTracker->pConnEle->RemoteName;
  2903. pTracker->UnicodeDestName = NULL; // We don't need unicode for NetBIOS name queries
  2904. //
  2905. // For a ReQuery request, DestIp is 0, otherwise for the ReTarget
  2906. // case, DestIp is the new destination address
  2907. //
  2908. if (DestIp) {
  2909. //
  2910. // Retarget
  2911. //
  2912. status = FindNameOrQuery(pTracker->pConnEle->RemoteName,
  2913. pDeviceContext,
  2914. SessionSetupContinue,
  2915. pTracker,
  2916. (ULONG) (NAMETYPE_UNIQUE | NAMETYPE_GROUP | NAMETYPE_INET_GROUP),
  2917. &IpAddress,
  2918. &pNameAddr,
  2919. REF_NAME_CONNECT,
  2920. FALSE);
  2921. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2922. KdPrint(("Nbt.NbtReConnect: name=<%16.16s:%x>, Status=%lx (%d of %s)\n",
  2923. pConnEle->RemoteName, pConnEle->RemoteName[15], status, __LINE__, __FILE__));
  2924. } else {
  2925. //
  2926. // This is the ReQuery attempt
  2927. //
  2928. BOOLEAN fNameReferenced = TRUE;
  2929. status = ContinueQueryNameOnNet (pTracker,
  2930. pTracker->pConnEle->RemoteName,
  2931. pDeviceContext,
  2932. SessionSetupContinue,
  2933. &fNameReferenced);
  2934. pNameAddr = pTracker->pNameAddr;
  2935. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2936. KdPrint(("Nbt.NbtReConnect: name=<%16.16s:%x>, Status=%lx (%d of %s)\n",
  2937. pConnEle->RemoteName, pConnEle->RemoteName[15], status, __LINE__, __FILE__));
  2938. }
  2939. NbtConnect_Check:
  2940. if ((status == STATUS_SUCCESS) && (!IpAddress)) {
  2941. ASSERT (0);
  2942. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, FALSE);
  2943. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: returns %!status!", pTracker, status));
  2944. status = STATUS_BAD_NETWORK_PATH;
  2945. }
  2946. if (status == STATUS_SUCCESS &&
  2947. IsDeviceNetbiosless(pTracker->pDeviceContext) &&
  2948. !IsSmbBoundToOutgoingInterface(IpAddress)) {
  2949. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, FALSE);
  2950. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: Fail requests on unbound SmbDevice", pTracker));
  2951. status = STATUS_BAD_NETWORK_PATH;
  2952. }
  2953. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2954. //
  2955. // be sure that a close or disconnect has not come down and
  2956. // cancelled the tracker
  2957. //
  2958. if (status == STATUS_PENDING) {
  2959. // i.e. pending was returned rather than success
  2960. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2961. CTEExReleaseResource(&NbtConfig.Resource);
  2962. return(status);
  2963. }
  2964. if (status == STATUS_SUCCESS) {
  2965. if (DestIp) {
  2966. IpAddress = DestIp;
  2967. }
  2968. if ((pTracker->Flags & TRACKER_CANCELLED)) {
  2969. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, TRUE);
  2970. status = STATUS_CANCELLED;
  2971. } else {
  2972. // set the session state to NBT_CONNECTING
  2973. CHECK_PTR(pTracker->pConnEle);
  2974. SET_STATE_UPPER (pTracker->pConnEle, NBT_CONNECTING);
  2975. pTracker->pConnEle->BytesRcvd = 0;;
  2976. pTracker->pConnEle->ReceiveIndicated = 0;
  2977. IF_DBG(NBT_DEBUG_NAMESRV)
  2978. KdPrint(("Nbt.NbtReConnect: Setting Up Session(cached entry!!) to %16.16s <%X>, %p\n",
  2979. pNameAddr->Name,pNameAddr->Name[15], pConnEle));
  2980. CHECK_PTR(pConnEle);
  2981. // keep track of the other end's ip address
  2982. // There may be a valid name address to use or it may have been
  2983. // nulled out to signify "Do Another Name Query"
  2984. pConnEle->pLowerConnId->SrcIpAddr = htonl(IpAddress);
  2985. SET_STATE_LOWER (pConnEle->pLowerConnId, NBT_CONNECTING);
  2986. pTracker->pTrackerWorker = NULL;
  2987. //
  2988. // We need to keep the pNameAddr data available for RAS
  2989. //
  2990. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_AUTODIAL);
  2991. pTracker->RemoteIpAddress = IpAddress;
  2992. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2993. status = TcpSessionStart(pTracker,
  2994. IpAddress,
  2995. (tDEVICECONTEXT *)pTracker->pDeviceContext,
  2996. SessionStartupContinue,
  2997. pTracker->DestPort);
  2998. CTEExReleaseResource(&NbtConfig.Resource);
  2999. //
  3000. // if TcpSessionStart fails for some reason it will still
  3001. // call the completion routine which will look after
  3002. // cleaning up
  3003. //
  3004. #ifdef RASAUTODIAL
  3005. //
  3006. // Notify the automatic connection driver
  3007. // of the successful connection.
  3008. //
  3009. if (fAcdLoadedG && NT_SUCCESS(status))
  3010. {
  3011. CTELockHandle adirql;
  3012. BOOLEAN fEnabled;
  3013. CTEGetLock(&AcdDriverG.SpinLock, &adirql);
  3014. fEnabled = AcdDriverG.fEnabled;
  3015. CTEFreeLock(&AcdDriverG.SpinLock, adirql);
  3016. if (fEnabled) {
  3017. NbtNoteNewConnection(pNameAddr, pDeviceContext->IpAddress);
  3018. }
  3019. }
  3020. #endif // RASAUTODIAL
  3021. //
  3022. // pNameAddr was referenced above for RAS, so deref it now!
  3023. //
  3024. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_AUTODIAL, FALSE);
  3025. return(status);
  3026. }
  3027. }
  3028. //
  3029. // *** Error Handling Here ***
  3030. //
  3031. // ** We are still holding the JointLock **
  3032. // unlink from the active connection list and put on idle list
  3033. //
  3034. CHECK_PTR(pConnEle);
  3035. RelistConnection(pConnEle);
  3036. CTESpinLock(pConnEle,OldIrq1);
  3037. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  3038. pConnEle->pIrp = NULL;
  3039. if (pLowerConn = pConnEle->pLowerConnId) {
  3040. CHECK_PTR(pLowerConn);
  3041. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  3042. // need to increment the ref count for DelayedCleanupAfterDisconnect to
  3043. // work correctly since it assumes the connection got fully connected
  3044. //
  3045. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  3046. ASSERT(pLowerConn->RefCount == 2);
  3047. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  3048. if (NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT)) {
  3049. pDeviceContext = pLowerConn->pDeviceContext;
  3050. } else {
  3051. pDeviceContext = NULL;
  3052. }
  3053. NTQueueToWorkerThread(
  3054. &pLowerConn->WorkItemCleanUpAndWipeOut,
  3055. DelayedCleanupAfterDisconnect,
  3056. NULL,
  3057. pLowerConn,
  3058. NULL,
  3059. pDeviceContext,
  3060. TRUE);
  3061. }
  3062. CTESpinFree(pConnEle,OldIrq1);
  3063. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3064. CTEExReleaseResource(&NbtConfig.Resource);
  3065. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  3066. //
  3067. // Undo the two references done above
  3068. //
  3069. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  3070. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  3071. return(status);
  3072. }
  3073. //----------------------------------------------------------------------------
  3074. extern
  3075. VOID
  3076. DelayedReConnect(
  3077. IN tDGRAM_SEND_TRACKING *pTracker,
  3078. IN PVOID DestAddr,
  3079. IN PVOID pUnused1,
  3080. IN tDEVICECONTEXT *pUnused2
  3081. )
  3082. /*++
  3083. Routine Description:
  3084. This Routine handles seting up a DPC to send a session pdu so that the stack
  3085. does not get wound up in multiple sends for the keep alive timeout case.
  3086. Arguments:
  3087. pIrp - a ptr to an IRP
  3088. Return Value:
  3089. NTSTATUS - status of the request
  3090. --*/
  3091. {
  3092. NTSTATUS status;
  3093. tCONNECTELE *pConnEle;
  3094. CTELockHandle OldIrq;
  3095. PCTE_IRP pIrp;
  3096. CHECK_PTR(pTracker);
  3097. // for retarget this is the destination address to connect to.
  3098. pConnEle = pTracker->pConnEle;
  3099. pTracker->pTimer = NULL;
  3100. if (pTracker->Flags & TRACKER_CANCELLED)
  3101. {
  3102. CTELockHandle OldIrq1;
  3103. //
  3104. // the connection setup got cancelled, return the connect irp
  3105. //
  3106. CTESpinLock(pConnEle,OldIrq1);
  3107. if (pIrp = pConnEle->pIrp)
  3108. {
  3109. pConnEle->pIrp = NULL;
  3110. CTESpinFree(pConnEle,OldIrq1);
  3111. CTEIoComplete(pIrp,STATUS_CANCELLED,0);
  3112. }
  3113. else
  3114. {
  3115. CTESpinFree(pConnEle,OldIrq1);
  3116. }
  3117. //
  3118. // if SessionSetupContinue has run, it has set the refcount to zero
  3119. //
  3120. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  3121. if (pTracker->RefConn == 0)
  3122. {
  3123. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3124. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  3125. }
  3126. else
  3127. {
  3128. pTracker->RefConn--;
  3129. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3130. }
  3131. return;
  3132. }
  3133. PUSH_LOCATION(0x85);
  3134. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  3135. status = NbtReConnect(pTracker, PtrToUlong(DestAddr));
  3136. if (!NT_SUCCESS(status))
  3137. {
  3138. // Reset the Irp pending flag
  3139. // No need to do this - pending has already be returned.
  3140. //CTEResetIrpPending(pConnEle->pIrp);
  3141. //
  3142. // tell the client that the session setup failed
  3143. //
  3144. CTELockHandle OldIrq1;
  3145. CTESpinLock(pConnEle,OldIrq1);
  3146. if (pIrp = pConnEle->pIrp)
  3147. {
  3148. pConnEle->pIrp = NULL;
  3149. CTESpinFree(pConnEle,OldIrq1);
  3150. CTEIoComplete( pIrp, STATUS_REMOTE_NOT_LISTENING, 0 ) ;
  3151. } else {
  3152. CTESpinFree(pConnEle,OldIrq1);
  3153. }
  3154. }
  3155. }
  3156. //----------------------------------------------------------------------------
  3157. NTSTATUS
  3158. NbtConnect(
  3159. IN TDI_REQUEST *pRequest,
  3160. IN PVOID pTimeout,
  3161. IN PTDI_CONNECTION_INFORMATION pCallInfo,
  3162. IN PIRP pIrp
  3163. )
  3164. /*++
  3165. Routine Description:
  3166. This Routine handles setting up a connection (netbios session) to
  3167. destination. This routine is also called by the Reconnect code when
  3168. doing a Retarget or trying to reach a destination that does not have
  3169. a listen currently posted. In this case the parameters mean different
  3170. things. pIrp could be a new Ipaddress to use (Retarget) and pCallinfo
  3171. will be null.
  3172. Arguments:
  3173. Return Value:
  3174. TDI_STATUS - status of the request
  3175. --*/
  3176. {
  3177. tCONNECTELE *pConnEle;
  3178. NTSTATUS status;
  3179. CTELockHandle OldIrq;
  3180. BOOLEAN fNoIpAddress;
  3181. pConnEle = pRequest->Handle.ConnectionContext;
  3182. NbtTrace(NBT_TRACE_OUTBOUND, ("TDI_CONNECT: pIrp %p pConnEle %p pClientEle %p",
  3183. pIrp, pConnEle, pConnEle->pClientEle));
  3184. if (!pConnEle->pClientEle) {
  3185. return (STATUS_INVALID_DEVICE_REQUEST);
  3186. }
  3187. ASSERT(pCallInfo);
  3188. //
  3189. // this code handles the When DHCP has not assigned an IP address yet
  3190. //
  3191. fNoIpAddress = (!pConnEle->pClientEle->pDeviceContext->pSessionFileObject) ||
  3192. (pConnEle->pClientEle->pDeviceContext->IpAddress == 0);
  3193. #ifdef RASAUTODIAL
  3194. if (fNoIpAddress && fAcdLoadedG) {
  3195. CTELockHandle adirql;
  3196. BOOLEAN fEnabled;
  3197. //
  3198. // There is no IP address assigned to the interface,
  3199. // attempt to create an automatic connection.
  3200. //
  3201. CTEGetLock(&AcdDriverG.SpinLock, &adirql);
  3202. fEnabled = AcdDriverG.fEnabled;
  3203. CTEFreeLock(&AcdDriverG.SpinLock, adirql);
  3204. if (fEnabled)
  3205. {
  3206. //
  3207. // Set a special cancel routine on the irp
  3208. // in case we get cancelled during the
  3209. // automatic connection.
  3210. //
  3211. (VOID)NbtSetCancelRoutine( pIrp, NbtCancelPreConnect, pConnEle->pClientEle->pDeviceContext);
  3212. if (NbtAttemptAutoDial(
  3213. pConnEle,
  3214. pTimeout,
  3215. pCallInfo,
  3216. pIrp,
  3217. 0,
  3218. NbtRetryPreConnect))
  3219. {
  3220. return STATUS_PENDING;
  3221. }
  3222. //
  3223. // We did not enqueue the irp on the
  3224. // automatic connection driver, so
  3225. // clear the cancel routine we set
  3226. // above.
  3227. //
  3228. (VOID)NbtCancelCancelRoutine(pIrp);
  3229. }
  3230. }
  3231. #endif // RASAUTODIAL
  3232. if (fNoIpAddress) {
  3233. NbtTrace(NBT_TRACE_OUTBOUND, ("returns STATUS_BAD_NETWORK_PATH"));
  3234. return(STATUS_BAD_NETWORK_PATH);
  3235. }
  3236. // check the connection element for validity
  3237. CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status)
  3238. return NbtConnectCommon(pRequest, pTimeout, pCallInfo, pIrp);
  3239. }
  3240. //----------------------------------------------------------------------------
  3241. NTSTATUS
  3242. NbtConnectCommon(
  3243. IN TDI_REQUEST *pRequest,
  3244. IN PVOID pTimeout,
  3245. IN PTDI_CONNECTION_INFORMATION pCallInfo,
  3246. IN PIRP pIrp
  3247. )
  3248. /*++
  3249. Routine Description:
  3250. This Routine handles setting up a connection (netbios session) to
  3251. destination. This routine is also called by the DelayedReconnect code when
  3252. doing a Retarget or trying to reach a destination that does not have
  3253. a listen currently posted. In this case the parameters mean different
  3254. things. pIrp could be a new Ipaddress to use (Retarget) and pCallinfo
  3255. will be null.
  3256. Arguments:
  3257. Return Value:
  3258. TDI_STATUS - status of the request
  3259. --*/
  3260. {
  3261. TDI_ADDRESS_NETBT_INTERNAL TdiAddr;
  3262. tCONNECTELE *pConnEle;
  3263. NTSTATUS status;
  3264. CTELockHandle OldIrq;
  3265. CTELockHandle OldIrq1;
  3266. CTELockHandle OldIrq2;
  3267. tIPADDRESS IpAddress;
  3268. PCHAR pToName;
  3269. USHORT sLength;
  3270. tSESSIONREQ *pSessionReq = NULL;
  3271. PUCHAR pCopyTo;
  3272. tCLIENTELE *pClientEle;
  3273. ULONG NameLen;
  3274. tDGRAM_SEND_TRACKING *pTracker, *pQueryTracker;
  3275. tNAMEADDR *pNameAddr;
  3276. tLOWERCONNECTION *pLowerConn;
  3277. tDEVICECONTEXT *pDeviceContext;
  3278. NBT_WORK_ITEM_CONTEXT *pContext;
  3279. tIPADDRESS RemoteIpAddress;
  3280. tLOWERCONNECTION *pLowerDump;
  3281. PLIST_ENTRY pEntry;
  3282. PCHAR pSessionName;
  3283. tDEVICECONTEXT *pDeviceContextOut = NULL;
  3284. #ifdef _PNP_POWER_
  3285. if (NbtConfig.Unloading) {
  3286. KdPrint (("Nbt.NbtConnectCommon: --> ERROR New Connect request while Unloading!!!\n"));
  3287. return STATUS_INSUFFICIENT_RESOURCES;
  3288. }
  3289. #endif // _PNP_POWER_
  3290. #ifdef DBG
  3291. {
  3292. PIO_STACK_LOCATION pIrpSp;
  3293. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  3294. ASSERT(pIrpSp && pIrpSp->CompletionRoutine == NbtpConnectCompletionRoutine);
  3295. }
  3296. #endif
  3297. ASSERT (pCallInfo);
  3298. /* If it is from local Irp, we always send an internal address format */
  3299. if (pCallInfo->RemoteAddressLength < sizeof (TA_NETBT_INTERNAL_ADDRESS)) {
  3300. ASSERT (0);
  3301. return (STATUS_INVALID_ADDRESS);
  3302. }
  3303. ASSERT(((PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress)->Address[0].AddressType == TDI_ADDRESS_TYPE_UNSPEC);
  3304. CTEMemCopy(&TdiAddr,
  3305. (PTDI_ADDRESS_NETBT_INTERNAL)((PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress)->Address[0].Address,
  3306. sizeof(TdiAddr));
  3307. pToName = TdiAddr.OEMRemoteName.Buffer;
  3308. NameLen = TdiAddr.OEMRemoteName.Length;
  3309. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3310. KdPrint(("Nbt.NbtConnectCommon: Remote Name: %*.*s, Length=%d\n", NameLen, NameLen, pToName, NameLen));
  3311. pConnEle = pRequest->Handle.ConnectionContext;
  3312. if (RemoteIpAddress = Nbt_inet_addr(pToName, SESSION_SETUP_FLAG)) {
  3313. pDeviceContextOut = GetDeviceFromInterface (htonl(RemoteIpAddress), TRUE);
  3314. }
  3315. //
  3316. // Acquire this resource to co-ordinate with DHCP changing the IP
  3317. // address
  3318. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  3319. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  3320. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpIrp %p: pConnEle %p: Connecting to %!NBTNAME!<%02x>",
  3321. pIrp, pConnEle, pToName, (unsigned)pToName[15]));
  3322. if ((!(NBT_VERIFY_HANDLE(pConnEle, NBT_VERIFY_CONNECTION))) || (!(pClientEle = pConnEle->pClientEle))) {
  3323. KdPrint (("Nbt.NbtConnectCommon: --> ERROR Address not associated for pConnEle=<%p>\n", pConnEle));
  3324. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpIrp %p: ERROR Address not associated", pIrp));
  3325. if (pDeviceContextOut) {
  3326. NBT_DEREFERENCE_DEVICE (pDeviceContextOut, REF_DEV_OUT_FROM_IP, TRUE);
  3327. }
  3328. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3329. CTEExReleaseResource(&NbtConfig.Resource);
  3330. return(STATUS_INVALID_ADDRESS);
  3331. }
  3332. CTESpinLock(pClientEle,OldIrq1);
  3333. CTESpinLock(pConnEle,OldIrq);
  3334. pDeviceContext = pClientEle->pDeviceContext;
  3335. status = CheckConnect(pConnEle, pClientEle, pDeviceContext);
  3336. if (status != STATUS_SUCCESS) {
  3337. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpIrp %p: CheckConnect return %!status!", pIrp, status));
  3338. pConnEle->pIrp = NULL;
  3339. CTESpinFree(pConnEle,OldIrq);
  3340. CTESpinFree(pClientEle,OldIrq1);
  3341. if (pDeviceContextOut) {
  3342. NBT_DEREFERENCE_DEVICE (pDeviceContextOut, REF_DEV_OUT_FROM_IP, TRUE);
  3343. }
  3344. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3345. CTEExReleaseResource(&NbtConfig.Resource);
  3346. return status;
  3347. }
  3348. if (RemoteIpAddress && NbtConfig.ConnectOnRequestedInterfaceOnly &&
  3349. !IsDeviceNetbiosless(pDeviceContext) && pDeviceContext != pDeviceContextOut) {
  3350. pConnEle->pIrp = NULL;
  3351. CTESpinFree(pConnEle,OldIrq);
  3352. CTESpinFree(pClientEle,OldIrq1);
  3353. if (pDeviceContextOut) {
  3354. NBT_DEREFERENCE_DEVICE (pDeviceContextOut, REF_DEV_OUT_FROM_IP, TRUE);
  3355. }
  3356. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3357. CTEExReleaseResource(&NbtConfig.Resource);
  3358. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpIrp %p: %!ipaddr! because Outgoing interface != RequestedInterface",
  3359. pIrp, RemoteIpAddress));
  3360. return STATUS_BAD_NETWORK_PATH;
  3361. }
  3362. SET_STATE_UPPER (pConnEle, NBT_CONNECTING);
  3363. // Increment the ref count so that a cleanup cannot remove
  3364. // the pConnEle till the session is setup - one of these is removed when
  3365. // the session is setup and the other is removed when it is disconnected.
  3366. //
  3367. NBT_REFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  3368. NBT_REFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  3369. ASSERT(pConnEle->RefCount >= 3);
  3370. //
  3371. // unlink the connection from the idle connection list and put on active list
  3372. //
  3373. RemoveEntryList(&pConnEle->Linkage);
  3374. InsertTailList(&pClientEle->ConnectActive,&pConnEle->Linkage);
  3375. // this field is used to hold a disconnect irp if it comes down during
  3376. // NBT_CONNECTING or NBT_SESSION_OUTBOUND states
  3377. //
  3378. pConnEle->pIrpDisc = NULL;
  3379. // we must store the client's irp in the connection element so that when
  3380. // the session sets up, we can complete the Irp.
  3381. ASSERT (pIrp);
  3382. pConnEle->pIrp = (PVOID) pIrp;
  3383. pConnEle->Orig = TRUE;
  3384. pConnEle->SessionSetupCount = NBT_SESSION_SETUP_COUNT-1; // -1 for this attempt
  3385. pConnEle->pClientEle->AddressType = TdiAddr.AddressType;
  3386. pConnEle->AddressType = TdiAddr.AddressType;
  3387. //
  3388. // Save the remote name while we still have it
  3389. //
  3390. CTEMemCopy (pConnEle->RemoteName, pToName, NETBIOS_NAME_SIZE);
  3391. if (TdiAddr.OEMEndpointName.Buffer) {
  3392. CTEMemCopy (pConnEle->pClientEle->EndpointName, TdiAddr.OEMEndpointName.Buffer, NETBIOS_NAME_SIZE);
  3393. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpIrp %p: Endpoint %!NBTNAME!<%02lx>",
  3394. pIrp,
  3395. TdiAddr.OEMEndpointName.Buffer,
  3396. TdiAddr.OEMEndpointName.Buffer[NETBIOS_NAME_SIZE-1]));
  3397. }
  3398. // get a buffer for tracking Session setup
  3399. status = GetTracker(&pTracker, NBT_TRACKER_CONNECT);
  3400. if (!NT_SUCCESS(status)) {
  3401. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  3402. status = STATUS_INSUFFICIENT_RESOURCES;
  3403. goto ExitProc;
  3404. }
  3405. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3406. KdPrint(("Nbt.NbtConnectCommon: Tracker %lx\n",pTracker));
  3407. // the length of the Session Request Pkt is the 4 byte session hdr length + the
  3408. // half ascii calling and called names + the scope length times 2, one for each name
  3409. //
  3410. sLength = (USHORT) (sizeof(tSESSIONREQ) + (NETBIOS_NAME_SIZE << 2) + (NbtConfig.ScopeLength <<1));
  3411. pTracker->pNetbiosUnicodeEX = TdiAddr.pNetbiosUnicodeEX;
  3412. pTracker->UnicodeRemoteName = NULL;
  3413. if (TdiAddr.pNetbiosUnicodeEX) {
  3414. pTracker->ucRemoteName = TdiAddr.pNetbiosUnicodeEX->RemoteName;
  3415. ASSERT((pTracker->ucRemoteName.MaximumLength % sizeof(WCHAR)) == 0);
  3416. ASSERT((pTracker->ucRemoteName.Length % sizeof(WCHAR)) == 0);
  3417. if (TdiAddr.pNetbiosUnicodeEX->NameBufferType != NBT_WRITEONLY) {
  3418. pTracker->UnicodeRemoteName = NbtAllocMem(pTracker->ucRemoteName.MaximumLength, NBT_TAG('F'));
  3419. if (pTracker->UnicodeRemoteName) {
  3420. pTracker->UnicodeRemoteNameLength = pTracker->ucRemoteName.Length;
  3421. CTEMemCopy(pTracker->UnicodeRemoteName, pTracker->ucRemoteName.Buffer,
  3422. pTracker->ucRemoteName.Length+sizeof(WCHAR));
  3423. }
  3424. }
  3425. // we ignore the failure because it isn't a critical feature. This failure only cause us not able to
  3426. // take advantage of the UNICODE information and return the resolved DNS name to RDR.
  3427. } else {
  3428. pTracker->ucRemoteName.Buffer = NULL;
  3429. pTracker->ucRemoteName.Length = 0;
  3430. pTracker->ucRemoteName.MaximumLength = 0;
  3431. }
  3432. /*
  3433. * Other netbt routines always assume that we have at least 16 bytes
  3434. * for remote name.
  3435. */
  3436. if (NameLen < NETBIOS_NAME_SIZE) {
  3437. pTracker->pRemoteName = NbtAllocMem(NETBIOS_NAME_SIZE, NBT_TAG('F'));
  3438. } else {
  3439. pTracker->pRemoteName = NbtAllocMem(NameLen, NBT_TAG('F'));
  3440. }
  3441. pSessionReq = (tSESSIONREQ *)NbtAllocMem(sLength,NBT_TAG('G'));
  3442. if (pTracker->pRemoteName == NULL || pSessionReq == NULL) {
  3443. if (pTracker->pRemoteName) {
  3444. CTEMemFree(pTracker->pRemoteName);
  3445. pTracker->pRemoteName = NULL;
  3446. }
  3447. if (pTracker->UnicodeRemoteName) {
  3448. CTEMemFree(pTracker->UnicodeRemoteName);
  3449. pTracker->UnicodeRemoteName = NULL;
  3450. }
  3451. if (pSessionReq) {
  3452. CTEMemFree(pSessionReq);
  3453. pSessionReq = NULL;
  3454. }
  3455. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  3456. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  3457. status = STATUS_INSUFFICIENT_RESOURCES;
  3458. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3459. goto ExitProc;
  3460. }
  3461. CTEMemCopy (pTracker->pRemoteName, pToName, NameLen);
  3462. pTracker->RemoteNameLength = NameLen; // May be needed for Dns Name resolution
  3463. pTracker->pDestName = pTracker->pRemoteName;
  3464. pTracker->UnicodeDestName = pTracker->UnicodeRemoteName; // bug #20697, #95241
  3465. pTracker->SendBuffer.pBuffer = pTracker->pRemoteName;
  3466. pTracker->SendBuffer.Length = 0;
  3467. pTracker->SendBuffer.pDgramHdr = pSessionReq;
  3468. // this is a ptr to the name in the client's, Irp, so that address must
  3469. // remain valid until this completes. It should be valid, because we
  3470. // do not complete the Irp until the transaction completes. This ptr
  3471. // is overwritten when the name resolves, so that it points the the
  3472. // pNameAddr in the hash table.
  3473. //
  3474. pTracker->RefCount = 1;
  3475. pTracker->RefConn = 1;
  3476. pTracker->pClientIrp = pIrp;
  3477. pTracker->pTimeout = pTimeout; // the timeout value is passed on through to the transport
  3478. pTracker->Flags = SESSION_SETUP_FLAG;
  3479. pTracker->pDeviceContext = pDeviceContext;
  3480. pTracker->pConnEle = pConnEle;
  3481. #ifdef _NETBIOSLESS
  3482. pTracker->DestPort = pDeviceContext->SessionPort; // Port to Send to
  3483. #else
  3484. pTracker->DestPort = NBT_SESSION_TCP_PORT;
  3485. #endif
  3486. #ifndef VXD
  3487. if (pConnEle->pClientEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX)
  3488. {
  3489. pSessionName = pConnEle->pClientEle->EndpointName;
  3490. }
  3491. else
  3492. #endif
  3493. {
  3494. pSessionName = pToName;
  3495. }
  3496. pSessionReq->Hdr.Type = NBT_SESSION_REQUEST;
  3497. pSessionReq->Hdr.Flags = NBT_SESSION_FLAGS;
  3498. pSessionReq->Hdr.Length = (USHORT)htons(sLength-(USHORT)sizeof(tSESSIONHDR)); // size of called and calling NB names.
  3499. pTracker->SendBuffer.HdrLength = (ULONG)sLength;
  3500. // put the Dest HalfAscii name into the Session Pdu
  3501. pCopyTo = ConvertToHalfAscii ((PCHAR)&pSessionReq->CalledName.NameLength,
  3502. pSessionName,
  3503. NbtConfig.pScope,
  3504. NbtConfig.ScopeLength);
  3505. // put the Source HalfAscii name into the Session Pdu
  3506. pCopyTo = ConvertToHalfAscii (pCopyTo,
  3507. ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name,
  3508. NbtConfig.pScope,
  3509. NbtConfig.ScopeLength);
  3510. // store the tracker in the Irp Rcv ptr so it can be used by the
  3511. // session setup code in hndlrs.c in the event the destination is
  3512. // between posting listens and this code should re-attempt the
  3513. // session setup. The code in hndlrs.c returns the tracker to its
  3514. // free list and frees the session hdr memory too.
  3515. //
  3516. // We need to set this while holding the ConnEle lock because the client
  3517. // can call NbtDisconnect while we are opening a Tcp handle and try to
  3518. // set the Tracker's flag to TRACKER_CANCELLED
  3519. //
  3520. pConnEle->pIrpRcv = (PIRP)pTracker;
  3521. CTESpinFree(pConnEle,OldIrq);
  3522. CTESpinFree(pClientEle,OldIrq1);
  3523. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3524. // open a connection with the transport for this session
  3525. status = NbtOpenAndAssocConnection (pDeviceContext, pConnEle, &pConnEle->pLowerConnId, '3');
  3526. if (!NT_SUCCESS(status)) {
  3527. goto NbtConnect_Check;
  3528. }
  3529. // We need to track that this side originated the call so we discard this
  3530. // connection at the end
  3531. //
  3532. pConnEle->pLowerConnId->bOriginator = TRUE;
  3533. // set this state to associated so that the cancel irp routine
  3534. // can differentiate the name query stage from the setupconnection
  3535. // stage since pConnEle is in the Nbtconnecting state for both.
  3536. //
  3537. SET_STATE_LOWER (pConnEle->pLowerConnId, NBT_ASSOCIATED);
  3538. // if this routine is called to do a reconnect, DO NOT close another
  3539. // Lower Connection since one was closed the on the first
  3540. // connect attempt.
  3541. //
  3542. // remove a lower connection from the free list attached to the device
  3543. // context since when this pConnEle was created, a lower connectin
  3544. // was created then incase inbound calls were to be accepted on the
  3545. // connection. But since it is an outbound call, remove a lower
  3546. // connection.
  3547. //
  3548. CTESpinLock(&NbtConfig.JointLock,OldIrq2); // Need this for DerefLowerConn
  3549. CTESpinLock(pDeviceContext,OldIrq1);
  3550. if (!pConnEle->LowerConnBlockRemoved &&
  3551. !IsListEmpty(&pDeviceContext->LowerConnFreeHead))
  3552. {
  3553. pEntry = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
  3554. pLowerDump = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
  3555. InterlockedDecrement (&pDeviceContext->NumFreeLowerConnections);
  3556. pConnEle->LowerConnBlockRemoved = TRUE;
  3557. //
  3558. // close the lower connection with the transport
  3559. //
  3560. IF_DBG(NBT_DEBUG_NAMESRV)
  3561. KdPrint(("Nbt.NbtConnectCommon: On Connect, close handle for pLower=<%p>\n", pLowerDump));
  3562. NBT_DEREFERENCE_LOWERCONN (pLowerDump, REF_LOWC_CREATE, TRUE);
  3563. }
  3564. CTESpinFree(pDeviceContext,OldIrq1);
  3565. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3566. //
  3567. // Check if the destination name is an IP address
  3568. //
  3569. #ifndef VXD
  3570. if (RemoteIpAddress)
  3571. {
  3572. //
  3573. // Tell Outbound() not to schedule a re-connect attempt when a negative response is received.
  3574. // Otherwise, we may end up with indefinitely loop
  3575. //
  3576. pTracker->ResolutionContextFlags = 0xFF;
  3577. //
  3578. // If the Address type is TDI_ADDRESS_TYPE_NETBIOS_EX, we have
  3579. // been given a specific endpoint to use, so try to setup the
  3580. // session using that Endpoint only
  3581. //
  3582. if (pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX)
  3583. {
  3584. //
  3585. // add this IP address to the remote hashtable
  3586. //
  3587. status = LockAndAddToHashTable(NbtConfig.pRemoteHashTbl,
  3588. pToName,
  3589. NbtConfig.pScope,
  3590. RemoteIpAddress,
  3591. NBT_UNIQUE,
  3592. NULL,
  3593. NULL,
  3594. pDeviceContextOut,
  3595. NAME_RESOLVED_BY_IP);
  3596. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3597. KdPrint(("Nbt.NbtConnectCommon: AddRecordToHashTable <%-16.16s:%x>, Status %x\n",
  3598. pToName, pToName[15], status));
  3599. if (NT_SUCCESS (status)) // SUCCESS if added first time, PENDING if name already existed!
  3600. {
  3601. SessionSetupContinue(pTracker, STATUS_SUCCESS);
  3602. status = STATUS_PENDING;
  3603. } else {
  3604. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3605. }
  3606. }
  3607. //
  3608. // Address type is TDI_ADDRESS_TYPE_NETBIOS
  3609. // The endpoint name is the same as the IP address, so send a NodeStatus
  3610. // request to the remote machine to get a proper Endpoint name
  3611. //
  3612. else
  3613. {
  3614. //
  3615. // NbtSendNodeStatus will either return Pending or error -- it
  3616. // should never return success!
  3617. //
  3618. pTracker->CompletionRoutine = SessionSetupContinue;
  3619. status = NbtSendNodeStatus(pDeviceContext,
  3620. pToName,
  3621. NULL,
  3622. pTracker,
  3623. ExtractServerNameCompletion);
  3624. if (!NT_SUCCESS(status)) {
  3625. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3626. }
  3627. }
  3628. }
  3629. else // the name is not an IP address!
  3630. #endif
  3631. {
  3632. if (NameLen <= NETBIOS_NAME_SIZE) {
  3633. status = FindNameOrQuery(pToName,
  3634. pDeviceContext,
  3635. SessionSetupContinue,
  3636. pTracker,
  3637. (ULONG) (NAMETYPE_UNIQUE | NAMETYPE_GROUP | NAMETYPE_INET_GROUP),
  3638. &IpAddress,
  3639. &pNameAddr,
  3640. REF_NAME_CONNECT,
  3641. FALSE);
  3642. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3643. KdPrint(("Nbt.NbtConnectCommon: name=<%*.*s:%x>, Len=%d, Status=%lx (%d of %s)\n",
  3644. NameLen, NameLen, pConnEle->RemoteName,
  3645. pConnEle->RemoteName[15], NameLen, status, __LINE__, __FILE__));
  3646. if (!NT_SUCCESS(status)) {
  3647. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3648. } else if (NULL != pNameAddr && NULL != pNameAddr->FQDN.Buffer &&
  3649. pTracker->pNetbiosUnicodeEX &&
  3650. (pTracker->pNetbiosUnicodeEX->NameBufferType == NBT_READWRITE ||
  3651. pTracker->pNetbiosUnicodeEX->NameBufferType == NBT_WRITEONLY)) {
  3652. USHORT NameLength, MaxLength;
  3653. NameLength = pNameAddr->FQDN.Length;
  3654. MaxLength = pTracker->pNetbiosUnicodeEX->RemoteName.MaximumLength;
  3655. if ((SHORT)NameLength > (SHORT)(MaxLength - sizeof(WCHAR))) {
  3656. NameLength = MaxLength - sizeof(WCHAR);
  3657. }
  3658. if ((SHORT)NameLength >= 0) {
  3659. CTEMemCopy(pTracker->pNetbiosUnicodeEX->RemoteName.Buffer,
  3660. pNameAddr->FQDN.Buffer, NameLength);
  3661. pTracker->pNetbiosUnicodeEX->RemoteName.Buffer[NameLength/sizeof(WCHAR)] = L'\0';
  3662. pTracker->pNetbiosUnicodeEX->RemoteName.Length = NameLength;
  3663. pTracker->pNetbiosUnicodeEX->NameBufferType = NBT_WRITTEN;
  3664. }
  3665. }
  3666. }
  3667. //
  3668. // if the name is longer than 16 bytes, it's not a netbios name.
  3669. // skip wins, broadcast etc. and go straight to dns resolution
  3670. // Also, we would go to DNS if the request came over the SmbDevice
  3671. //
  3672. #ifdef _NETBIOSLESS
  3673. if ((NameLen > NETBIOS_NAME_SIZE) ||
  3674. ((IsDeviceNetbiosless(pDeviceContext)) && (!NT_SUCCESS(status))))
  3675. #else
  3676. if (NameLen > NETBIOS_NAME_SIZE)
  3677. #endif
  3678. {
  3679. pTracker->AddressType = pConnEle->AddressType;
  3680. #ifndef VXD
  3681. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  3682. KdPrint(("Nbt.NbtConnectCommon: $$$$$ DNS for NETBIOS name=<%*.*s:%x>, Len=%d, Status=%lx (%d of %s)\n",
  3683. NameLen, NameLen, pConnEle->RemoteName,
  3684. pConnEle->RemoteName[15], NameLen, status, __LINE__, __FILE__));
  3685. #endif
  3686. if (pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('H'))) {
  3687. pContext->pTracker = NULL; // no query tracker
  3688. pContext->pClientContext = pTracker; // the client tracker
  3689. pContext->ClientCompletion = SessionSetupContinue;
  3690. pContext->pDeviceContext = pDeviceContext;
  3691. //
  3692. // Start the timer so that the request does not hang waiting for Dns!
  3693. //
  3694. StartLmHostTimer(pContext, FALSE);
  3695. status = NbtProcessLmhSvcRequest (pContext, NBT_RESOLVE_WITH_DNS);
  3696. if (!NT_SUCCESS (status)) {
  3697. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3698. CTEMemFree(pContext);
  3699. }
  3700. } else {
  3701. status = STATUS_INSUFFICIENT_RESOURCES;
  3702. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3703. }
  3704. }
  3705. }
  3706. NbtConnect_Check:
  3707. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status! %!ipaddr!", pIrp, pTracker, status, IpAddress));
  3708. if ((status == STATUS_SUCCESS) && (!IpAddress)) {
  3709. ASSERT(0);
  3710. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, FALSE);
  3711. status = STATUS_BAD_NETWORK_PATH;
  3712. }
  3713. if (status == STATUS_SUCCESS &&
  3714. IsDeviceNetbiosless(pTracker->pDeviceContext) &&
  3715. !IsSmbBoundToOutgoingInterface(IpAddress)) {
  3716. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, FALSE);
  3717. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3718. status = STATUS_BAD_NETWORK_PATH;
  3719. }
  3720. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  3721. if (pDeviceContextOut) {
  3722. NBT_DEREFERENCE_DEVICE (pDeviceContextOut, REF_DEV_OUT_FROM_IP, TRUE);
  3723. pDeviceContextOut = NULL;
  3724. }
  3725. //
  3726. // be sure that a close or disconnect has not come down and
  3727. // cancelled the tracker
  3728. //
  3729. if (status == STATUS_PENDING) {
  3730. // i.e. pending was returned rather than success
  3731. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3732. CTEExReleaseResource(&NbtConfig.Resource);
  3733. return(status);
  3734. }
  3735. if (status == STATUS_SUCCESS)
  3736. {
  3737. if ((pTracker->Flags & TRACKER_CANCELLED))
  3738. {
  3739. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, TRUE);
  3740. status = STATUS_CANCELLED;
  3741. }
  3742. else // connect as long as we have an IP address (even to group names)
  3743. {
  3744. // set the session state to NBT_CONNECTING
  3745. CHECK_PTR(pTracker->pConnEle);
  3746. SET_STATE_UPPER (pTracker->pConnEle, NBT_CONNECTING);
  3747. pTracker->pConnEle->BytesRcvd = 0;;
  3748. pTracker->pConnEle->ReceiveIndicated = 0;
  3749. IF_DBG(NBT_DEBUG_NAMESRV)
  3750. KdPrint(("Nbt.NbtConnectCommon: Setting Up Session(cached entry!!) to %16.16s <%X>, %p\n",
  3751. pNameAddr->Name,pNameAddr->Name[15], pConnEle));
  3752. CHECK_PTR(pConnEle);
  3753. // keep track of the other end's ip address
  3754. // There may be a valid name address to use or it may have been
  3755. // nulled out to signify "Do Another Name Query"
  3756. pConnEle->pLowerConnId->SrcIpAddr = htonl(IpAddress);
  3757. SET_STATE_LOWER (pConnEle->pLowerConnId, NBT_CONNECTING);
  3758. pTracker->pTrackerWorker = NULL;
  3759. //
  3760. // We need to keep the pNameAddr data available for RAS
  3761. //
  3762. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_AUTODIAL);
  3763. pTracker->RemoteIpAddress = IpAddress;
  3764. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3765. status = TcpSessionStart(pTracker,
  3766. IpAddress,
  3767. (tDEVICECONTEXT *)pTracker->pDeviceContext,
  3768. SessionStartupContinue,
  3769. pTracker->DestPort);
  3770. CTEExReleaseResource(&NbtConfig.Resource);
  3771. //
  3772. // if TcpSessionStart fails for some reason it will still
  3773. // call the completion routine which will look after
  3774. // cleaning up
  3775. //
  3776. #ifdef RASAUTODIAL
  3777. //
  3778. // Notify the automatic connection driver
  3779. // of the successful connection.
  3780. //
  3781. if (fAcdLoadedG && NT_SUCCESS(status))
  3782. {
  3783. CTELockHandle adirql;
  3784. BOOLEAN fEnabled;
  3785. CTEGetLock(&AcdDriverG.SpinLock, &adirql);
  3786. fEnabled = AcdDriverG.fEnabled;
  3787. CTEFreeLock(&AcdDriverG.SpinLock, adirql);
  3788. if (fEnabled)
  3789. {
  3790. NbtNoteNewConnection(pNameAddr, pDeviceContext->IpAddress);
  3791. }
  3792. }
  3793. #endif // RASAUTODIAL
  3794. //
  3795. // pNameAddr was referenced above for RAS, so deref it now!
  3796. //
  3797. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_AUTODIAL, FALSE);
  3798. return(status);
  3799. }
  3800. }
  3801. //
  3802. // *** Error Handling Here ***
  3803. //
  3804. // ** We are still holding the JointLock **
  3805. // unlink from the active connection list and put on idle list
  3806. //
  3807. CHECK_PTR(pConnEle);
  3808. RelistConnection(pConnEle);
  3809. CTESpinLock(pConnEle,OldIrq1);
  3810. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  3811. pConnEle->pIrp = NULL;
  3812. if (pLowerConn = pConnEle->pLowerConnId)
  3813. {
  3814. CHECK_PTR(pLowerConn);
  3815. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  3816. // need to increment the ref count for DelayedCleanupAfterDisconnect to
  3817. // work correctly since it assumes the connection got fully connected
  3818. //
  3819. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  3820. ASSERT(pLowerConn->RefCount == 2);
  3821. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  3822. if (NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT))
  3823. {
  3824. pDeviceContext = pLowerConn->pDeviceContext;
  3825. }
  3826. else
  3827. {
  3828. pDeviceContext = NULL;
  3829. }
  3830. NTQueueToWorkerThread(
  3831. &pLowerConn->WorkItemCleanUpAndWipeOut,
  3832. DelayedCleanupAfterDisconnect,
  3833. NULL,
  3834. pLowerConn,
  3835. NULL,
  3836. pDeviceContext,
  3837. TRUE
  3838. );
  3839. }
  3840. CTESpinFree(pConnEle,OldIrq1);
  3841. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3842. CTEExReleaseResource(&NbtConfig.Resource);
  3843. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  3844. //
  3845. // Undo the two references done above
  3846. //
  3847. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  3848. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  3849. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3850. return(status);
  3851. ExitProc:
  3852. pConnEle->pIrp = NULL;
  3853. //
  3854. // Put the connection back on the idle connection list
  3855. //
  3856. RemoveEntryList(&pConnEle->Linkage);
  3857. InsertTailList(&pClientEle->ConnectHead,&pConnEle->Linkage);
  3858. CTESpinFree(pConnEle,OldIrq);
  3859. CTESpinFree(pClientEle,OldIrq1);
  3860. if (pDeviceContextOut) {
  3861. NBT_DEREFERENCE_DEVICE (pDeviceContextOut, REF_DEV_OUT_FROM_IP, TRUE);
  3862. pDeviceContextOut = NULL;
  3863. }
  3864. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3865. CTEExReleaseResource(&NbtConfig.Resource);
  3866. //
  3867. // Undo the two references done above
  3868. //
  3869. NBT_DEREFERENCE_CONNECTION(pConnEle, REF_CONN_SESSION);
  3870. NBT_DEREFERENCE_CONNECTION(pConnEle, REF_CONN_CONNECT);
  3871. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p %!status!", pIrp, pTracker, status));
  3872. return(status);
  3873. }
  3874. //----------------------------------------------------------------------------
  3875. VOID
  3876. CleanUpPartialConnection(
  3877. IN NTSTATUS status,
  3878. IN tCONNECTELE *pConnEle,
  3879. IN tDGRAM_SEND_TRACKING *pTracker,
  3880. IN PIRP pClientIrp,
  3881. IN CTELockHandle irqlJointLock,
  3882. IN CTELockHandle irqlConnEle
  3883. )
  3884. {
  3885. CTELockHandle OldIrq;
  3886. CTELockHandle OldIrq1;
  3887. PIRP pIrpDisc;
  3888. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p pConnEle %p %!status!",
  3889. pClientIrp, pTracker, pConnEle, status));
  3890. if (pConnEle->state != NBT_IDLE)
  3891. {
  3892. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  3893. }
  3894. //
  3895. // If the tracker is cancelled then NbtDisconnect has run and there is
  3896. // a disconnect irp waiting to be returned.
  3897. //
  3898. pIrpDisc = NULL;
  3899. if (pTracker->Flags & TRACKER_CANCELLED)
  3900. {
  3901. //
  3902. // Complete the disconnect irp now too
  3903. //
  3904. pIrpDisc = pConnEle->pIrpDisc;
  3905. status = STATUS_CANCELLED;
  3906. }
  3907. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  3908. //
  3909. // this will close the lower connection and dereference pConnEle once.
  3910. //
  3911. QueueCleanup (pConnEle, &irqlJointLock, &irqlConnEle);
  3912. CTESpinFree(pConnEle,irqlConnEle);
  3913. //
  3914. // If the state is IDLE it means that NbtCleanupConnection has run and
  3915. // the connection has been removed from the list so don't add it to
  3916. // the list again
  3917. //
  3918. if (pConnEle->state != NBT_IDLE)
  3919. {
  3920. RelistConnection(pConnEle);
  3921. }
  3922. CTESpinFree(&NbtConfig.JointLock,irqlJointLock);
  3923. //
  3924. // remove the last reference added in nbt connect. The refcount will be 2
  3925. // if nbtcleanupconnection has not run and 1, if it has. So this call
  3926. // could free pConnEle.
  3927. //
  3928. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  3929. NbtTrace(NBT_TRACE_OUTBOUND, ("pIrp %p: pTracker %p pConnEle %p %!status!",
  3930. pClientIrp, pTracker, pConnEle, status));
  3931. if (status == STATUS_TIMEOUT)
  3932. {
  3933. status = STATUS_BAD_NETWORK_PATH;
  3934. }
  3935. CTEIoComplete(pClientIrp,status,0L);
  3936. //
  3937. // This is a disconnect irp that has been queued till the name query
  3938. // completed
  3939. //
  3940. if (pIrpDisc)
  3941. {
  3942. NbtTrace(NBT_TRACE_OUTBOUND, ("TDI_DISCONNECT pIrp %p", pIrpDisc));
  3943. CTEIoComplete(pIrpDisc,STATUS_SUCCESS,0L);
  3944. }
  3945. }
  3946. //----------------------------------------------------------------------------
  3947. VOID
  3948. SessionSetupContinue(
  3949. IN PVOID pContext,
  3950. IN NTSTATUS status
  3951. )
  3952. /*++
  3953. Routine Description
  3954. This routine handles setting up a session after a name has been resolved
  3955. to an IP address.
  3956. This routine is given as the completion routine to the "QueryNameOnNet" call
  3957. in NbtConnect, above. When a name query response comes in or the
  3958. timer times out after N retries, this routine is called passing STATUS_TIMEOUT
  3959. for a failure.
  3960. Arguments:
  3961. pContext - ptr to the DGRAM_TRACKER block
  3962. NTSTATUS - completion status
  3963. Return Values:
  3964. VOID
  3965. --*/
  3966. {
  3967. tDGRAM_SEND_TRACKING *pTracker;
  3968. CTELockHandle OldIrq;
  3969. CTELockHandle OldIrq1;
  3970. tNAMEADDR *pNameAddr = NULL;
  3971. ULONG lNameType;
  3972. PIRP pClientIrp;
  3973. PIRP pIrpDisc;
  3974. ULONG IpAddress;
  3975. tCONNECTELE *pConnEle;
  3976. tLOWERCONNECTION *pLowerConn;
  3977. tDEVICECONTEXT *pDeviceContext;
  3978. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  3979. pConnEle = pTracker->pConnEle;
  3980. CHECK_PTR(pConnEle);
  3981. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  3982. if (NT_SUCCESS(status)) {
  3983. /*
  3984. * Find the NameAddr and reference it
  3985. */
  3986. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  3987. CTESpinLock(pConnEle,OldIrq);
  3988. lNameType = NAMETYPE_UNIQUE;
  3989. pNameAddr = FindNameRemoteThenLocal(pTracker, &IpAddress, &lNameType);
  3990. if (pNameAddr) {
  3991. // increment so the name cannot disappear and to be consistent
  3992. // with FindNameOrQuery , which increments the refcount, so
  3993. // we always need to deref it when the connection is setup.
  3994. //
  3995. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT);
  3996. // DEBUG
  3997. ASSERT(pNameAddr->RefCount >= 2);
  3998. } else {
  3999. status = STATUS_BAD_NETWORK_PATH;
  4000. }
  4001. CTESpinFree(pConnEle,OldIrq);
  4002. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  4003. }
  4004. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!ipaddr! %!status!", pTracker, IpAddress, status));
  4005. /*
  4006. * IsSmbBoundToOutgoingInterface won't work with JointLock held
  4007. */
  4008. if (NT_SUCCESS(status) &&
  4009. IsDeviceNetbiosless(pTracker->pDeviceContext) &&
  4010. !IsSmbBoundToOutgoingInterface(IpAddress)) {
  4011. /* This status may be changed into STATUS_CANCELLED below */
  4012. status = STATUS_BAD_NETWORK_PATH;
  4013. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: Client not bound to NetbiosSmb", pTracker));
  4014. }
  4015. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  4016. CTESpinLock(pConnEle,OldIrq);
  4017. if ((pTracker->Flags & TRACKER_CANCELLED) ||
  4018. (!(pLowerConn = pConnEle->pLowerConnId)) || // The lower connection could have been cleaned up!
  4019. (!NBT_VERIFY_HANDLE(pTracker->pDeviceContext, NBT_VERIFY_DEVCONTEXT)))
  4020. {
  4021. status = STATUS_CANCELLED;
  4022. }
  4023. // this is the QueryOnNet Tracker ptr being cleared rather than the
  4024. // session setup tracker.
  4025. //
  4026. pTracker->pTrackerWorker = NULL;
  4027. if (status == STATUS_SUCCESS)
  4028. {
  4029. // check the Remote table and then the Local table
  4030. // a session can only be started with a unique named destination
  4031. //
  4032. if (lNameType & (NAMETYPE_UNIQUE | NAMETYPE_GROUP | NAMETYPE_INET_GROUP))
  4033. {
  4034. // set the session state, initialize a few things and setup a
  4035. // TCP connection, calling SessionStartupContinue when the TCP
  4036. // connection is up
  4037. //
  4038. CHECK_PTR(pConnEle);
  4039. SET_STATE_LOWER (pLowerConn, NBT_CONNECTING);
  4040. SET_STATE_UPPER (pConnEle, NBT_CONNECTING);
  4041. pConnEle->BytesRcvd = 0;;
  4042. pConnEle->ReceiveIndicated = 0;
  4043. CHECK_PTR(pTracker);
  4044. pTracker->pNameAddr = pNameAddr;
  4045. if (NULL == pNameAddr->FQDN.Buffer && pTracker->pNetbiosUnicodeEX &&
  4046. pTracker->pNetbiosUnicodeEX->NameBufferType == NBT_WRITTEN) {
  4047. //
  4048. // FQDN is available
  4049. // Save it into the pNameAddr
  4050. //
  4051. pNameAddr->FQDN.Buffer = NbtAllocMem(
  4052. pTracker->pNetbiosUnicodeEX->RemoteName.Length + sizeof(WCHAR),
  4053. NBT_TAG('F'));
  4054. if (NULL != pNameAddr->FQDN.Buffer) {
  4055. pNameAddr->FQDN.Length = pTracker->pNetbiosUnicodeEX->RemoteName.Length;
  4056. pNameAddr->FQDN.MaximumLength = pNameAddr->FQDN.Length + sizeof(WCHAR);
  4057. CTEMemCopy(pNameAddr->FQDN.Buffer,
  4058. pTracker->pNetbiosUnicodeEX->RemoteName.Buffer,
  4059. pNameAddr->FQDN.Length
  4060. );
  4061. pNameAddr->FQDN.Buffer[pNameAddr->FQDN.Length/sizeof(WCHAR)] = L'\0';
  4062. }
  4063. }
  4064. // keep track of the other end's ip address
  4065. pConnEle->pLowerConnId->SrcIpAddr = htonl(IpAddress);
  4066. IF_DBG(NBT_DEBUG_NAMESRV)
  4067. KdPrint(("Nbt.SessionSetupContinue: Setting Up Session(after Query) to %16.16s <%X>, %p\n",
  4068. pNameAddr->Name,pNameAddr->Name[15],
  4069. pTracker->pConnEle));
  4070. ASSERT(pNameAddr->RefCount >= 2);
  4071. //
  4072. // increment pNameAddr once more since we may need to access
  4073. // it below for RAS sessions
  4074. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_AUTODIAL);
  4075. pDeviceContext = pTracker->pDeviceContext;
  4076. pTracker->RemoteIpAddress = IpAddress;
  4077. CTESpinFree(pConnEle,OldIrq);
  4078. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  4079. // start the session...
  4080. status = TcpSessionStart (pTracker,
  4081. IpAddress,
  4082. (tDEVICECONTEXT *)pTracker->pDeviceContext,
  4083. SessionStartupContinue,
  4084. pTracker->DestPort);
  4085. //
  4086. // the only failure that could occur is if the pLowerConn
  4087. // got separated from pConnEle, in which case some other
  4088. // part of the code has disconnected and cleanedup, so
  4089. // just return
  4090. //
  4091. #ifdef RASAUTODIAL
  4092. //
  4093. // Notify the automatic connection driver
  4094. // of the successful connection.
  4095. //
  4096. if (fAcdLoadedG && NT_SUCCESS(status))
  4097. {
  4098. CTELockHandle adirql;
  4099. BOOLEAN fEnabled;
  4100. CTEGetLock(&AcdDriverG.SpinLock, &adirql);
  4101. fEnabled = AcdDriverG.fEnabled;
  4102. CTEFreeLock(&AcdDriverG.SpinLock, adirql);
  4103. if (fEnabled)
  4104. {
  4105. NbtNoteNewConnection(pNameAddr, pDeviceContext->IpAddress);
  4106. }
  4107. }
  4108. #endif // RASAUTODIAL
  4109. //
  4110. // pNameAddr was referenced above for RAS, so deref it now!
  4111. //
  4112. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_AUTODIAL, FALSE);
  4113. return;
  4114. }
  4115. status = STATUS_BAD_NETWORK_PATH;
  4116. }
  4117. if (pNameAddr) {
  4118. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT, TRUE);
  4119. }
  4120. pClientIrp = pConnEle->pIrp;
  4121. pConnEle->pIrp = NULL;
  4122. if (STATUS_REMOTE_NOT_LISTENING != status) // set in ExtractServerNameCompletion
  4123. {
  4124. status = STATUS_HOST_UNREACHABLE;
  4125. }
  4126. CleanUpPartialConnection(status, pConnEle, pTracker, pClientIrp, OldIrq1, OldIrq);
  4127. }
  4128. //----------------------------------------------------------------------------
  4129. VOID
  4130. QueueCleanup(
  4131. IN tCONNECTELE *pConnEle,
  4132. IN CTELockHandle *pOldIrqJointLock,
  4133. IN CTELockHandle *pOldIrqConnEle
  4134. )
  4135. /*++
  4136. Routine Description
  4137. This routine handles Queuing a request to a worker thread to cleanup
  4138. a connection(which basically closes the connection).
  4139. This routine is called with the JointLock + ConnEle locks held
  4140. and returns with them held
  4141. Arguments:
  4142. pConnEle - ptr to the upper connection
  4143. Return Values:
  4144. VOID
  4145. --*/
  4146. {
  4147. NTSTATUS status;
  4148. CTELockHandle OldIrq;
  4149. ULONG State;
  4150. BOOLEAN DerefConnEle;
  4151. tLOWERCONNECTION *pLowerConn;
  4152. tDEVICECONTEXT *pDeviceContext = NULL;
  4153. // to coordinate with RejectSession in hndlrs.c we are holding the spin lock
  4154. // so we don't disconnect twice.
  4155. //
  4156. if ((pLowerConn = pConnEle->pLowerConnId) &&
  4157. (pLowerConn->Verify == NBT_VERIFY_LOWERCONN) &&
  4158. (pLowerConn->State > NBT_IDLE) &&
  4159. (pLowerConn->State < NBT_DISCONNECTING))
  4160. {
  4161. CTESpinLock(pLowerConn,OldIrq);
  4162. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  4163. if (pLowerConn->Verify != NBT_VERIFY_LOWERCONN)
  4164. {
  4165. //
  4166. // The lower connection block has already been cleaned up
  4167. // or is waiting to be cleaned up, so just return!
  4168. //
  4169. // MALAM_FIX: Fix this so that we don't have to dereference the LowerConn to find this out.
  4170. // One scenario where this happens is if the device gets destroyed in DelayedNbtDeleteDevice
  4171. // and we end up dereferencing the lowerconn which causes it to get deleted!
  4172. // ASSERT(0);
  4173. CTESpinFree(pLowerConn,OldIrq);
  4174. return;
  4175. }
  4176. IF_DBG(NBT_DEBUG_DISCONNECT)
  4177. KdPrint(("Nbt.QueueCleanup: State=%X, Lower=%X Upper=%X\n",
  4178. pLowerConn->State, pLowerConn,pLowerConn->pUpperConnection));
  4179. CHECK_PTR(pLowerConn);
  4180. State = pLowerConn->State;
  4181. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTING);
  4182. if (pConnEle->state != NBT_IDLE)
  4183. {
  4184. SET_STATE_UPPER (pConnEle, NBT_DISCONNECTED);
  4185. }
  4186. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  4187. //
  4188. // need to increment the ref count for DelayedCleanupAfterDisconnect to
  4189. // work correctly since it assumes the connection got fully connected
  4190. // Note: if this routine is called AFTER the connection is fully
  4191. // connected such as in SessionStartupTimeout, then RefCount must
  4192. // be decremented there to account for this increment.
  4193. //
  4194. if (State < NBT_SESSION_OUTBOUND)
  4195. {
  4196. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  4197. }
  4198. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  4199. ASSERT (pLowerConn->RefCount > 1);
  4200. CTESpinFree(pLowerConn,OldIrq);
  4201. CTESpinFree(pConnEle,*pOldIrqConnEle);
  4202. if (NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT))
  4203. {
  4204. pDeviceContext = pLowerConn->pDeviceContext;
  4205. }
  4206. status = NTQueueToWorkerThread(
  4207. &pLowerConn->WorkItemCleanUpAndWipeOut,
  4208. DelayedCleanupAfterDisconnect,
  4209. NULL,
  4210. pLowerConn,
  4211. NULL,
  4212. pDeviceContext,
  4213. TRUE
  4214. );
  4215. CTESpinFree(&NbtConfig.JointLock,*pOldIrqJointLock);
  4216. //
  4217. // when the lower no longer points to the upper undo the reference
  4218. // done in NbtConnect, or InBound.
  4219. //
  4220. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  4221. CTESpinLock(&NbtConfig.JointLock,*pOldIrqJointLock);
  4222. CTESpinLock(pConnEle,*pOldIrqConnEle);
  4223. }
  4224. }
  4225. //----------------------------------------------------------------------------
  4226. extern
  4227. NTSTATUS
  4228. StartSessionTimer(
  4229. tDGRAM_SEND_TRACKING *pTracker,
  4230. tCONNECTELE *pConnEle
  4231. )
  4232. /*++
  4233. Routine Description
  4234. This routine handles setting up a timer to time the connection setup.
  4235. JointLock Spin Lock is held before calling this routine.
  4236. Arguments:
  4237. pConnEle - ptr to the connection structure
  4238. Return Values:
  4239. VOID
  4240. --*/
  4241. {
  4242. NTSTATUS status;
  4243. ULONG Timeout = 0;
  4244. CTELockHandle OldIrq;
  4245. CTESpinLock(pConnEle,OldIrq);
  4246. if (pTracker->pTimeout)
  4247. {
  4248. CTEGetTimeout(pTracker->pTimeout,&Timeout);
  4249. }
  4250. // now start a timer to time the return of the session setup
  4251. // message
  4252. //
  4253. IF_DBG(NBT_DEBUG_NAMESRV)
  4254. KdPrint(("Nbt.StartSessionTimer: TimeOut = %X\n",Timeout));
  4255. if (Timeout < NBT_SESSION_RETRY_TIMEOUT)
  4256. {
  4257. Timeout = NBT_SESSION_RETRY_TIMEOUT;
  4258. }
  4259. status = StartTimer(SessionStartupTimeout,
  4260. Timeout,
  4261. (PVOID)pTracker, // context value
  4262. NULL, // context2 value
  4263. pTracker,
  4264. SessionStartupTimeoutCompletion,
  4265. pConnEle->pDeviceContext,
  4266. &pTracker->pTimer,
  4267. 0,
  4268. TRUE);
  4269. if (!NT_SUCCESS(status))
  4270. {
  4271. // we failed to get a timer, but the timer is only used
  4272. // to handle the destination not responding to it is
  4273. // not critical to get a timer... so carry on
  4274. //
  4275. CHECK_PTR(pTracker);
  4276. pTracker->pTimer = NULL;
  4277. }
  4278. CTESpinFree(pConnEle,OldIrq);
  4279. return(status);
  4280. }
  4281. //----------------------------------------------------------------------------
  4282. VOID
  4283. SessionStartupContinue(
  4284. IN PVOID pContext,
  4285. IN NTSTATUS status,
  4286. IN ULONG lInfo)
  4287. /*++
  4288. Routine Description
  4289. This routine handles sending the session request PDU after the TCP
  4290. connection has been setup to the destination IP address.
  4291. Arguments:
  4292. pContext - ptr to the DGRAM_TRACKER block
  4293. NTSTATUS - completion status
  4294. Return Values:
  4295. VOID
  4296. --*/
  4297. {
  4298. tDGRAM_SEND_TRACKING *pTracker;
  4299. tCONNECTELE *pConnEle;
  4300. ULONG lSentLength;
  4301. TDI_REQUEST TdiRequest;
  4302. PIRP pClientIrp;
  4303. PIRP pIrpDisc = NULL;
  4304. tLOWERCONNECTION *pLowerConn;
  4305. CTELockHandle OldIrq;
  4306. CTELockHandle OldIrq1;
  4307. BOOLEAN fNameReferenced = TRUE; // In FindNameOrQuery or SessionSetupContinue
  4308. tNAMEADDR *pNameAddr;
  4309. tDEVICECONTEXT *pDeviceContext;
  4310. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  4311. pConnEle = (tCONNECTELE *)pTracker->pConnEle;
  4312. pDeviceContext = pTracker->pDeviceContext;
  4313. ASSERT (pTracker->Verify == NBT_VERIFY_TRACKER);
  4314. CHECK_PTR (pConnEle);
  4315. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  4316. CTESpinLock(pConnEle,OldIrq);
  4317. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  4318. if (pTracker->Flags & TRACKER_CANCELLED)
  4319. {
  4320. status = STATUS_CANCELLED;
  4321. pIrpDisc = pConnEle->pIrpDisc; // Complete the Disconnect Irp that is pending too
  4322. }
  4323. #ifdef MULTIPLE_WINS
  4324. //
  4325. // If we failed to establish a connection and we still have
  4326. // not finished querying all the Name Servers, then continue
  4327. // the Query process
  4328. //
  4329. if (NbtConfig.TryAllNameServers &&
  4330. #ifdef _NETBIOSLESS
  4331. (!IsDeviceNetbiosless(pDeviceContext)) &&
  4332. #endif
  4333. (pConnEle->pLowerConnId) &&
  4334. (status != STATUS_CANCELLED) &&
  4335. (!NT_SUCCESS(status)) &&
  4336. (pTracker->ResolutionContextFlags != NAME_RESOLUTION_DONE))
  4337. {
  4338. SET_STATE_LOWER (pConnEle->pLowerConnId, NBT_ASSOCIATED);
  4339. CTESpinFree(pConnEle,OldIrq);
  4340. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  4341. //
  4342. // See if we can get another IP address and re-try!
  4343. //
  4344. if (STATUS_PENDING == ContinueQueryNameOnNet (pTracker,
  4345. pTracker->pConnEle->RemoteName,
  4346. pDeviceContext,
  4347. SessionSetupContinue,
  4348. &fNameReferenced))
  4349. {
  4350. // i.e. pending was returned
  4351. return;
  4352. }
  4353. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  4354. CTESpinLock(pConnEle,OldIrq);
  4355. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  4356. }
  4357. #endif
  4358. //
  4359. // Set the pBuffer ptr = NULL so that we don't try to
  4360. // set it as the Mdl->Next ptr in TdiSend!
  4361. //
  4362. if (pTracker->SendBuffer.pBuffer)
  4363. {
  4364. pTracker->SendBuffer.pBuffer = NULL;
  4365. }
  4366. pLowerConn = pConnEle->pLowerConnId;
  4367. if ((NT_SUCCESS(status)) &&
  4368. (!pLowerConn))
  4369. {
  4370. // in case the connection got disconnected during the setup phase,
  4371. // check the lower conn value
  4372. status = STATUS_UNSUCCESSFUL;
  4373. }
  4374. //
  4375. // NbtDisconnect can cancel the tracker if a disconnect comes in during
  4376. // the connecting phase.
  4377. //
  4378. if (NT_SUCCESS(status))
  4379. {
  4380. #ifdef _NETBIOSLESS
  4381. // *****************************************************************
  4382. //
  4383. // Skip session setup for message only mode
  4384. //
  4385. if (IsDeviceNetbiosless(pDeviceContext))
  4386. {
  4387. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  4388. KdPrint(("Nbt.SessionStartupContinue: skipping session setup\n"));
  4389. // Here is where we fake out the data structures to move to the SESSION_UP state
  4390. // We enter holding jointLock and pConnEle lock
  4391. // zero out the number of bytes received so far, since this is a new connection
  4392. pConnEle->BytesRcvd = 0;
  4393. pConnEle->pIrpRcv = NULL;
  4394. pClientIrp = pConnEle->pIrp;
  4395. pConnEle->pIrp = NULL;
  4396. SET_STATE_UPPER (pConnEle, NBT_SESSION_UP);
  4397. CTESpinFree(pConnEle,OldIrq);
  4398. if (fNameReferenced)
  4399. {
  4400. //
  4401. // remove the reference done when FindNameOrQuery was called, or when
  4402. // SessionSetupContinue ran
  4403. //
  4404. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  4405. }
  4406. //
  4407. // Increment the reference count on a connection while it is connected
  4408. // so that it cannot be deleted until it disconnects.
  4409. //
  4410. CTESpinLock(pLowerConn,OldIrq);
  4411. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  4412. ASSERT(pLowerConn->RefCount == 2);
  4413. SET_STATE_LOWER (pLowerConn, NBT_SESSION_UP);
  4414. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  4415. CTESpinFree(pLowerConn,OldIrq);
  4416. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  4417. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  4418. // remove the reference added in nbt connect
  4419. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  4420. // NOTE: the last reference done on pConnEle in NbtConnect is NOT undone
  4421. // until the pLowerConn no longer points to pConnEle!!
  4422. // the assumption is that if the connect irp was cancelled then the
  4423. // client should be doing a disconnect or close shortly thereafter, so
  4424. // there is no error handling code here.
  4425. if (pClientIrp)
  4426. {
  4427. //
  4428. // complete the client's connect request Irp
  4429. //
  4430. #ifndef VXD
  4431. CTEIoComplete (pClientIrp, STATUS_SUCCESS, 0 ) ;
  4432. #else
  4433. CTEIoComplete (pClientIrp, STATUS_SUCCESS, (ULONG)pConnEle ) ;
  4434. #endif
  4435. }
  4436. return;
  4437. }
  4438. // *****************************************************************
  4439. #endif // _NETBIOSLESS
  4440. // set the session state to NBT_SESSION_OUTBOUND
  4441. //
  4442. SET_STATE_UPPER (pConnEle, NBT_SESSION_OUTBOUND);
  4443. //
  4444. // Increment the reference count on a connection while it is connected
  4445. // so that it cannot be deleted until it disconnects.
  4446. //
  4447. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  4448. ASSERT(pLowerConn->RefCount == 2);
  4449. SET_STATE_LOWER (pLowerConn, NBT_SESSION_OUTBOUND);
  4450. SET_STATERCV_LOWER (pLowerConn, NORMAL, Outbound);
  4451. // we need to pass the file handle of the connection to TCP.
  4452. TdiRequest.Handle.AddressHandle = pLowerConn->pFileObject;
  4453. // the completion routine is setup to free the pTracker memory block
  4454. TdiRequest.RequestNotifyObject = SessionStartupCompletion;
  4455. TdiRequest.RequestContext = (PVOID)pTracker;
  4456. CTESpinFree(pConnEle,OldIrq);
  4457. //
  4458. // failure to get a timer causes the connection setup to fail
  4459. //
  4460. status = StartSessionTimer(pTracker,pConnEle);
  4461. if (NT_SUCCESS(status))
  4462. {
  4463. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  4464. status = NbtSetCancelRoutine(pConnEle->pIrp, NbtCancelSession, pDeviceContext);
  4465. if (!NT_SUCCESS(status))
  4466. {
  4467. //
  4468. // We have closed down the connection by failing the call to
  4469. // setup up the cancel routine - it ended up calling the
  4470. // cancel routine.
  4471. //
  4472. //
  4473. // remove the second reference added in nbtconnect
  4474. //
  4475. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  4476. if (pTracker->RefConn == 0) {
  4477. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, FALSE);
  4478. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  4479. } else {
  4480. pTracker->RefConn--;
  4481. }
  4482. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  4483. return;
  4484. }
  4485. // the only data sent is the session request buffer which is in the pSendinfo
  4486. // structure.
  4487. status = TdiSend (&TdiRequest,
  4488. 0, // send flags are not set
  4489. pTracker->SendBuffer.HdrLength,
  4490. &lSentLength,
  4491. &pTracker->SendBuffer,
  4492. 0);
  4493. //
  4494. // the completion routine will get called with the errors and
  4495. // handle them appropriately, so just return here
  4496. //
  4497. return;
  4498. } else {
  4499. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  4500. }
  4501. CTESpinLock(pConnEle,OldIrq);
  4502. }
  4503. else
  4504. {
  4505. // if the remote station does not have a connection to receive the
  4506. // session pdu on , then we will get back this status. We may also
  4507. // get this if the destination does not have NBT running at all. This
  4508. // is a short timeout - 250 milliseconds, times 3.
  4509. //
  4510. }
  4511. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  4512. //
  4513. // this branch is taken if the TCP connection setup fails or the
  4514. // tracker has been cancelled.
  4515. //
  4516. CHECK_PTR(pConnEle);
  4517. pClientIrp = pConnEle->pIrp;
  4518. pConnEle->pIrp = NULL;
  4519. IF_DBG(NBT_DEBUG_DISCONNECT)
  4520. KdPrint(("Nbt.SessionStartupContinue: Failed, State=%X,TrackerFlags=%X pConnEle=%X\n",
  4521. pConnEle->state, pTracker->Flags, pConnEle));
  4522. //
  4523. // remove the name from the hash table since we did not connect
  4524. // (only if the request was not cancelled)!
  4525. //
  4526. //
  4527. // if it is in the remote table and still active...
  4528. // and no one else is referencing the name, then delete it from
  4529. // the hash table.
  4530. //
  4531. if (fNameReferenced)
  4532. {
  4533. if ((status != STATUS_CANCELLED) &&
  4534. (pTracker->pNameAddr->Verify == REMOTE_NAME) &&
  4535. (pTracker->pNameAddr->NameTypeState & STATE_RESOLVED) &&
  4536. (pTracker->pNameAddr->RefCount == 2))
  4537. {
  4538. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_REMOTE, TRUE);
  4539. }
  4540. //
  4541. // remove the reference done when FindNameOrQuery was called, or when
  4542. // SessionSetupContinue ran
  4543. //
  4544. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  4545. }
  4546. // Either the connection failed to get setup or the send on the
  4547. // connection failed, either way, don't mess with disconnects, just
  4548. // close the connection... If the Tracker was cancelled then it means
  4549. // someother part of the code has done the disconnect already.
  4550. //
  4551. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  4552. if (pConnEle->state != NBT_IDLE)
  4553. {
  4554. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  4555. }
  4556. // Cache the fact that an attempt to set up a TDI connection failed. This will enable us to
  4557. // weed out repeated attempts on the same remote address. The only case that is exempt is a
  4558. // NETBIOS name which we let it pass through because it adopts a different name resolution
  4559. // mechanism.
  4560. #ifndef VXD
  4561. if (pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX)
  4562. {
  4563. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  4564. KdPrint(("Nbt.SessionStartupContinue: Will avoid repeated attempts on a nonexistent address\n"));
  4565. pConnEle->RemoteNameDoesNotExistInDNS = TRUE;
  4566. }
  4567. if (status == STATUS_IO_TIMEOUT)
  4568. {
  4569. status = STATUS_HOST_UNREACHABLE;
  4570. }
  4571. else if (status == STATUS_CONNECTION_REFUSED)
  4572. {
  4573. if (IsDeviceNetbiosless(pDeviceContext))
  4574. {
  4575. status = STATUS_REMOTE_NOT_LISTENING;
  4576. }
  4577. else
  4578. {
  4579. status = STATUS_BAD_NETWORK_PATH;
  4580. }
  4581. }
  4582. #else
  4583. if (status == TDI_CONN_REFUSED || status == TDI_TIMED_OUT)
  4584. {
  4585. status = STATUS_BAD_NETWORK_PATH;
  4586. }
  4587. #endif
  4588. QueueCleanup (pConnEle, &OldIrq1, &OldIrq);
  4589. CTESpinFree(pConnEle,OldIrq);
  4590. //
  4591. // put back on the idle connection list if nbtcleanupconnection has not
  4592. // run and taken pconnele off the list (setting the state to Idle).
  4593. //
  4594. if (pConnEle->state != NBT_IDLE)
  4595. {
  4596. RelistConnection(pConnEle);
  4597. }
  4598. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  4599. //
  4600. // remove the last reference added in nbt connect. The refcount will be 2
  4601. // if nbtcleanupconnection has not run and 1, if it has. So this call
  4602. // could free pConnEle.
  4603. //
  4604. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  4605. // the cancel irp routine in Ntisol.c sets the irp to NULL if it cancels
  4606. // it.
  4607. if (pClientIrp)
  4608. {
  4609. CTEIoComplete(pClientIrp,status,0L);
  4610. }
  4611. if (pIrpDisc)
  4612. {
  4613. CTEIoComplete(pIrpDisc,STATUS_SUCCESS,0L);
  4614. }
  4615. }
  4616. //----------------------------------------------------------------------------
  4617. extern
  4618. VOID
  4619. SessionStartupCompletion(
  4620. IN PVOID pContext,
  4621. IN NTSTATUS status,
  4622. IN ULONG lInfo)
  4623. /*++
  4624. Routine Description
  4625. This routine handles the completion of sending the session request pdu.
  4626. It completes the Irp back to the client indicating the outcome of the
  4627. transaction if there is an error otherwise it keeps the irp till the
  4628. session setup response is heard.
  4629. Tracker block is put back on its free Q and the
  4630. session header is freed back to the non-paged pool.
  4631. Arguments:
  4632. pContext - ptr to the DGRAM_TRACKER block
  4633. NTSTATUS - completion status
  4634. Return Values:
  4635. VOID
  4636. --*/
  4637. {
  4638. tDGRAM_SEND_TRACKING *pTracker;
  4639. CTELockHandle OldIrq;
  4640. tCONNECTELE *pConnEle;
  4641. tLOWERCONNECTION *pLowerConn;
  4642. COMPLETIONCLIENT CompletionRoutine = NULL;
  4643. ULONG state;
  4644. PCTE_IRP pClientIrp;
  4645. PCTE_IRP pIrpDisc;
  4646. tTIMERQENTRY *pTimer;
  4647. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  4648. pConnEle = (tCONNECTELE *)pTracker->pConnEle;
  4649. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4650. pLowerConn = pConnEle->pLowerConnId;
  4651. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status! pConnEle %p pLowerConn %p",
  4652. pTracker, status, pConnEle, pLowerConn));
  4653. //
  4654. // if OutBound or the SessionStartupTimeoutCompletion have run,
  4655. // they have set the refcount to zero, so just cleanup!
  4656. //
  4657. if (pTracker->RefConn == 0)
  4658. {
  4659. //
  4660. // remove the reference done when FindNameOrQuery was called, or when
  4661. // SessionSetupContinue ran
  4662. //
  4663. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  4664. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  4665. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4666. }
  4667. else
  4668. {
  4669. pTracker->RefConn--;
  4670. //
  4671. // a failure status means that the transport could not send the
  4672. // session startup pdu - if this happens, then disconnect the
  4673. // connection and return the client's irp with the status code
  4674. //
  4675. if ((!NT_SUCCESS(status)))
  4676. {
  4677. // we must check the status first since it is possible that the
  4678. // lower connection has disappeared already due to a disconnect/cleanup
  4679. // in the VXD case anyway. Only for a bad status can we be sure
  4680. // that pConnEle is still valid.
  4681. //
  4682. CHECK_PTR(pTracker);
  4683. if (pTimer = pTracker->pTimer)
  4684. {
  4685. pTracker->pTimer = NULL;
  4686. StopTimer(pTimer,&CompletionRoutine,NULL);
  4687. }
  4688. IF_DBG(NBT_DEBUG_DISCONNECT)
  4689. KdPrint(("Nbt.SessionStartupCompletion: Failed, State=%X,TrackerFlags=%X CompletionRoutine=%X,pConnEle=%X\n",
  4690. pConnEle->state, pTracker->Flags, CompletionRoutine, pConnEle));
  4691. //
  4692. // Only if the timer has not expired yet do we kill off the connection
  4693. // since if the timer has expired, it has already done this in
  4694. // SessionStartupTimeout.
  4695. //
  4696. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4697. if (CompletionRoutine)
  4698. {
  4699. (*CompletionRoutine) (pTracker, status);
  4700. }
  4701. }
  4702. else
  4703. {
  4704. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4705. }
  4706. }
  4707. //
  4708. // remove the last reference added in nbt connect. The refcount
  4709. // will be 2 if nbtcleanupconnection has not run and 1, if it has. So this call
  4710. // could free pConnEle.
  4711. //
  4712. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION);
  4713. }
  4714. //----------------------------------------------------------------------------
  4715. VOID
  4716. SessionStartupTimeout(
  4717. PVOID pContext,
  4718. PVOID pContext2,
  4719. tTIMERQENTRY *pTimerQEntry
  4720. )
  4721. /*++
  4722. Routine Description:
  4723. This routine handles timing out a connection setup request. The timer
  4724. is started when the connection is started and the session setup
  4725. message is about to be sent.
  4726. Arguments:
  4727. Return Value:
  4728. The function value is the status of the operation.
  4729. --*/
  4730. {
  4731. tDGRAM_SEND_TRACKING *pTracker;
  4732. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  4733. // if pTimerQEntry is null then the timer is being cancelled, so do nothing
  4734. if (!pTimerQEntry)
  4735. {
  4736. pTracker->pTimer = NULL;
  4737. return;
  4738. }
  4739. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: SessionStartupTimeout", pTracker));
  4740. SessionStartupTimeoutCompletion (pTracker, STATUS_IO_TIMEOUT);
  4741. }
  4742. //----------------------------------------------------------------------------
  4743. VOID
  4744. SessionStartupTimeoutCompletion(
  4745. IN tDGRAM_SEND_TRACKING *pTracker,
  4746. IN NTSTATUS status
  4747. )
  4748. {
  4749. CTELockHandle OldIrq;
  4750. CTELockHandle OldIrq1;
  4751. CTELockHandle OldIrq2;
  4752. tCONNECTELE *pConnEle;
  4753. tLOWERCONNECTION *pLowerConn;
  4754. CTE_IRP *pIrp;
  4755. enum eSTATE State;
  4756. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status!", pTracker, status));
  4757. // kill the connection
  4758. //
  4759. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  4760. pTracker->pTimer = NULL;
  4761. if (!(pConnEle = pTracker->pConnEle) ||
  4762. !(pLowerConn = pConnEle->pLowerConnId) ||
  4763. !(pTracker == (tDGRAM_SEND_TRACKING *) pConnEle->pIrpRcv))
  4764. {
  4765. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4766. return;
  4767. }
  4768. NbtTrace(NBT_TRACE_OUTBOUND, ("pTracker %p: %!status! pConnEle %p pLowerConn %p",
  4769. pTracker, status, pConnEle, pLowerConn));
  4770. CHECK_PTR(pConnEle);
  4771. IF_DBG(NBT_DEBUG_DISCONNECT)
  4772. KdPrint(("Nbt.SessionStartupTimeout: pConnEle=<%x>-->State=<%x>\n", pConnEle, pConnEle->state));
  4773. IF_DBG(NBT_DEBUG_DISCONNECT)
  4774. KdPrint(("Nbt.SessionStartupTimeout: pLowerConn=<%x>-->State=<%x>, TrackerFlags=<%x>\n",
  4775. pLowerConn, pLowerConn->State, pTracker->Flags));
  4776. CTESpinLock(pConnEle,OldIrq2);
  4777. CTESpinLock(pLowerConn,OldIrq1);
  4778. if ((pConnEle->state != NBT_SESSION_OUTBOUND) ||
  4779. (!(pIrp = pConnEle->pIrp)))
  4780. {
  4781. CTESpinFree(pLowerConn,OldIrq1);
  4782. CTESpinFree(pConnEle,OldIrq2);
  4783. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4784. return;
  4785. }
  4786. pConnEle->pIrp = NULL;
  4787. State = pConnEle->state;
  4788. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  4789. NBT_REFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION_TIMEOUT);
  4790. pLowerConn->pUpperConnection = NULL; // So that any response for this in Outbound does not succeed
  4791. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  4792. CTESpinFree(pLowerConn,OldIrq1);
  4793. QueueCleanup (pConnEle, &OldIrq, &OldIrq2);
  4794. CTESpinFree(pConnEle,OldIrq2);
  4795. //
  4796. // Nbt_idle means that nbtcleanupConnection has run and the
  4797. // connection is about to be deleted, so don't relist.
  4798. //
  4799. if (State != NBT_IDLE)
  4800. {
  4801. RelistConnection(pConnEle);
  4802. }
  4803. //
  4804. // if SessionStartupCompletion has run, it has set the refcount to zero
  4805. //
  4806. if (pTracker->RefConn == 0)
  4807. {
  4808. if ((pTracker->pNameAddr->Verify == REMOTE_NAME) && // Remote names only!
  4809. (pTracker->pNameAddr->NameTypeState & STATE_RESOLVED) &&
  4810. (pTracker->pNameAddr->RefCount == 2))
  4811. {
  4812. //
  4813. // If no one else is referencing the name, then delete it from
  4814. // the hash table.
  4815. //
  4816. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_REMOTE, TRUE);
  4817. }
  4818. //
  4819. // remove the reference done when FindNameOrQuery was called, or when
  4820. // SessionSetupContinue ran
  4821. //
  4822. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  4823. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  4824. }
  4825. else
  4826. {
  4827. pTracker->RefConn--;
  4828. }
  4829. //
  4830. // remove the reference done when FindNameOrQuery was called, or when
  4831. // SessionSetupContinue ran
  4832. //
  4833. pConnEle->pIrpRcv = NULL; // So that SessionStartupCompletion does not also try to cleanup!
  4834. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  4835. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_SESSION_TIMEOUT);
  4836. CTEIoComplete(pIrp, status, 0);
  4837. }
  4838. //----------------------------------------------------------------------------
  4839. extern
  4840. VOID
  4841. RelistConnection(
  4842. IN tCONNECTELE *pConnEle
  4843. )
  4844. /*++
  4845. Routine Description
  4846. This routine unlinks the ConnEle from the ConnectActive list and puts it
  4847. back on the Connecthead. It is used when a connection goes to
  4848. NBT_ASSOCIATED state.
  4849. Arguments:
  4850. Return Values:
  4851. TDI_STATUS - status of the request
  4852. --*/
  4853. {
  4854. CTELockHandle OldIrq;
  4855. CTELockHandle OldIrq1;
  4856. tCLIENTELE *pClientEle = pConnEle->pClientEle;
  4857. //
  4858. // If pClientEle is NULL, it means the client was most probably
  4859. // cleaned up, and the connection should now be on the Device's
  4860. // UpConnectionInUse list
  4861. //
  4862. ASSERT (NBT_VERIFY_HANDLE2 (pConnEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN));
  4863. if (pClientEle)
  4864. {
  4865. CTESpinLock(pClientEle,OldIrq);
  4866. CTESpinLock(pConnEle,OldIrq1);
  4867. ASSERT (NBT_VERIFY_HANDLE2 (pClientEle, NBT_VERIFY_CLIENT, NBT_VERIFY_CLIENT_DOWN));
  4868. //
  4869. // if the state is NBT_IDLE it means that NbtCleanupConnection has run
  4870. // and removed the connection from its list in preparation for
  4871. // freeing the memory, so don't put it back on the list
  4872. //
  4873. if (pConnEle->state != NBT_IDLE)
  4874. {
  4875. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  4876. RemoveEntryList(&pConnEle->Linkage);
  4877. InsertTailList(&pConnEle->pClientEle->ConnectHead,&pConnEle->Linkage);
  4878. }
  4879. CTESpinFree(pConnEle,OldIrq1);
  4880. CTESpinFree(pClientEle,OldIrq);
  4881. }
  4882. }
  4883. //----------------------------------------------------------------------------
  4884. NTSTATUS
  4885. NbtSend(
  4886. IN TDI_REQUEST *pRequest,
  4887. IN USHORT Flags,
  4888. IN ULONG SendLength,
  4889. OUT LONG *pSentLength,
  4890. IN PVOID *pBuffer,
  4891. IN tDEVICECONTEXT *pContext,
  4892. IN PIRP pIrp
  4893. )
  4894. /*++
  4895. Routine Description
  4896. ... does nothing now....
  4897. Arguments:
  4898. Return Values:
  4899. TDI_STATUS - status of the request
  4900. --*/
  4901. {
  4902. //
  4903. // This routine is never hit since the NTISOL.C routine NTSEND actually
  4904. // bypasses this code and passes the send directly to the transport
  4905. //
  4906. ASSERT(0);
  4907. return(STATUS_SUCCESS);
  4908. }
  4909. //----------------------------------------------------------------------------
  4910. NTSTATUS
  4911. NbtListen(
  4912. IN TDI_REQUEST *pRequest,
  4913. IN ULONG Flags,
  4914. IN TDI_CONNECTION_INFORMATION *pRequestConnectInfo,
  4915. OUT TDI_CONNECTION_INFORMATION *pReturnConnectInfo,
  4916. IN PVOID pIrp)
  4917. /*++
  4918. Routine Description:
  4919. This Routine posts a listen on an open connection allowing a client to
  4920. indicate that is prepared to accept inbound connections. The ConnectInfo
  4921. may contain an address to specify which remote clients may connect to
  4922. the connection although we don't currently look at that info.
  4923. Arguments:
  4924. Return Value:
  4925. ReturnConnectInfo - status of the request
  4926. --*/
  4927. {
  4928. tCLIENTELE *pClientEle;
  4929. tCONNECTELE *pConnEle;
  4930. NTSTATUS status;
  4931. tLISTENREQUESTS *pListenReq;
  4932. CTELockHandle OldIrq;
  4933. CTELockHandle OldIrq1;
  4934. pListenReq = NbtAllocMem(sizeof(tLISTENREQUESTS),NBT_TAG('I'));
  4935. if (!pListenReq)
  4936. {
  4937. NbtTrace(NBT_TRACE_INBOUND, ("Out of memory"));
  4938. return(STATUS_INSUFFICIENT_RESOURCES);
  4939. }
  4940. // now find the connection object to link this listen record to
  4941. pConnEle = ((tCONNECTELE *)pRequest->Handle.ConnectionContext);
  4942. //
  4943. // Find the client record associated with this connection
  4944. //
  4945. if ((!NBT_VERIFY_HANDLE (pConnEle, NBT_VERIFY_CONNECTION)) || // NBT_VERIFY_CONNECTION_DOWN if cleaned up
  4946. (!NBT_VERIFY_HANDLE ((pClientEle = pConnEle->pClientEle), NBT_VERIFY_CLIENT)))
  4947. {
  4948. CTEMemFree(pListenReq);
  4949. NbtTrace(NBT_TRACE_INBOUND, ("Invalid Handle pConnEle<%p> pClientEle<%p>", pConnEle, pClientEle));
  4950. return(STATUS_INVALID_HANDLE);
  4951. }
  4952. CTESpinLock(pClientEle,OldIrq);
  4953. CTESpinLock(pConnEle,OldIrq1);
  4954. //
  4955. // Now reverify the Client and Connection handles, and ensure the Connection state is correct!
  4956. //
  4957. if ((!NBT_VERIFY_HANDLE (pConnEle, NBT_VERIFY_CONNECTION)) ||
  4958. (!NBT_VERIFY_HANDLE (pClientEle, NBT_VERIFY_CLIENT)) ||
  4959. (pConnEle->state != NBT_ASSOCIATED))
  4960. {
  4961. CTESpinFree(pConnEle,OldIrq1);
  4962. CTESpinFree(pClientEle,OldIrq);
  4963. CTEMemFree(pListenReq);
  4964. NbtTrace(NBT_TRACE_INBOUND, ("Invalid state %x", pConnEle->state));
  4965. return(STATUS_INVALID_HANDLE);
  4966. }
  4967. //
  4968. // Fill in the Listen request
  4969. //
  4970. pListenReq->pIrp = pIrp;
  4971. pListenReq->Flags = Flags;
  4972. pListenReq->pConnectEle = pConnEle;
  4973. pListenReq->pConnInfo = pRequestConnectInfo;
  4974. pListenReq->pReturnConnInfo = pReturnConnectInfo;
  4975. pListenReq->CompletionRoutine = pRequest->RequestNotifyObject;
  4976. pListenReq->Context = pRequest->RequestContext;
  4977. // queue the listen request on the client object
  4978. InsertTailList(&pClientEle->ListenHead,&pListenReq->Linkage);
  4979. status = NTCheckSetCancelRoutine(pIrp,(PVOID)NbtCancelListen,0);
  4980. NbtTrace(NBT_TRACE_INBOUND, ("NTCheckSetCancelRoutine return %!status! for %!NBTNAME!<%02x>",
  4981. status, pClientEle->pAddress->pNameAddr->Name,
  4982. (unsigned)pClientEle->pAddress->pNameAddr->Name[15]));
  4983. if (!NT_SUCCESS(status))
  4984. {
  4985. RemoveEntryList(&pListenReq->Linkage);
  4986. status = STATUS_CANCELLED;
  4987. }
  4988. else
  4989. {
  4990. status = STATUS_PENDING;
  4991. }
  4992. CTESpinFree(pConnEle,OldIrq1);
  4993. CTESpinFree(pClientEle,OldIrq);
  4994. return(status);
  4995. }
  4996. //----------------------------------------------------------------------------
  4997. NTSTATUS
  4998. NbtDisconnect(
  4999. IN TDI_REQUEST *pRequest,
  5000. IN PVOID pTimeout,
  5001. IN ULONG Flags,
  5002. IN PTDI_CONNECTION_INFORMATION pCallInfo,
  5003. IN PTDI_CONNECTION_INFORMATION pReturnInfo,
  5004. IN PIRP pIrp)
  5005. /*++
  5006. Routine Description:
  5007. This Routine handles taking down a connection (netbios session).
  5008. Arguments:
  5009. Return Value:
  5010. TDI_STATUS - status of the request
  5011. --*/
  5012. {
  5013. tCONNECTELE *pConnEle;
  5014. NTSTATUS status;
  5015. CTELockHandle OldIrq;
  5016. CTELockHandle OldIrq2;
  5017. CTELockHandle OldIrq3;
  5018. tLOWERCONNECTION *pLowerConn;
  5019. ULONG LowerState = NBT_IDLE;
  5020. ULONG StateRcv;
  5021. BOOLEAN Originator = TRUE;
  5022. PCTE_IRP pClientIrp = NULL;
  5023. BOOLEAN RelistIt = FALSE;
  5024. BOOLEAN Wait;
  5025. PCTE_IRP pIrpDisc;
  5026. pConnEle = pRequest->Handle.ConnectionContext;
  5027. IF_DBG(NBT_DEBUG_NAMESRV)
  5028. KdPrint(("Nbt.NbtDisconnect: state %X %X\n",pConnEle->state,pConnEle));
  5029. // check the connection element for validity
  5030. //CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status)
  5031. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  5032. if ((pConnEle->state <= NBT_ASSOCIATED) ||
  5033. (pConnEle->state >= NBT_DISCONNECTING))
  5034. {
  5035. // the connection is not connected so reject the disconnect attempt
  5036. // ( with an Invalid Connection return code ) - unless there is a
  5037. // value stored in the flag
  5038. // DiscFlag field which will be the status of a previous
  5039. // disconnect indication from the transport.
  5040. //
  5041. if ((pConnEle->DiscFlag))
  5042. {
  5043. if (Flags == TDI_DISCONNECT_WAIT)
  5044. {
  5045. if (pConnEle->DiscFlag == TDI_DISCONNECT_ABORT)
  5046. {
  5047. status = STATUS_CONNECTION_RESET;
  5048. }
  5049. else
  5050. {
  5051. status = STATUS_GRACEFUL_DISCONNECT;
  5052. }
  5053. }
  5054. else
  5055. {
  5056. status = STATUS_SUCCESS;
  5057. }
  5058. // clear the flag now.
  5059. CHECK_PTR(pConnEle);
  5060. pConnEle->DiscFlag = 0;
  5061. }
  5062. else
  5063. {
  5064. status = STATUS_CONNECTION_INVALID;
  5065. }
  5066. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5067. return(status);
  5068. }
  5069. // to link and unlink upper and lower connections the Joint lock must
  5070. // be held. This allows coordination from the lower side and from
  5071. // the upper side. - i.e. once the joint lock is held, the upper and lower
  5072. // connections cannot become unlinked.
  5073. //
  5074. CTESpinLock(pConnEle,OldIrq2);
  5075. // Do this check with the spin lock held to avoid a race condition
  5076. // with a disconnect coming in from the transport at the same time.
  5077. //
  5078. pLowerConn = pConnEle->pLowerConnId;
  5079. //
  5080. // a disconnect wait is not really a disconnect, it is just there so that
  5081. // when a disconnect occurs, the transport will complete it, and indicate
  5082. // to the client there is a disconnect (instead of having a disconnect
  5083. // indication handler) - therefore, for Disc Wait, do NOT change state.
  5084. //
  5085. CHECK_PTR(pConnEle);
  5086. pIrpDisc = pConnEle->pIrpDisc;
  5087. pConnEle->pIrpDisc = NULL;
  5088. if (Flags == TDI_DISCONNECT_WAIT)
  5089. {
  5090. //
  5091. // save the Irp here and wait for a disconnect to return it
  5092. // to the client.
  5093. //
  5094. if ((pConnEle->state == NBT_SESSION_UP) &&
  5095. (!pConnEle->pIrpClose))
  5096. {
  5097. pConnEle->pIrpClose = pIrp;
  5098. status = STATUS_PENDING;
  5099. //
  5100. // call this routine to check if the cancel flag has been
  5101. // already set and therefore we must return the irp now
  5102. //
  5103. status = NbtSetCancelRoutine(pIrp, NbtCancelDisconnectWait,pLowerConn->pDeviceContext);
  5104. //
  5105. // change the ret status so if the irp has been cancelled,
  5106. // driver.c will not also return it, since NbtSetCancelRoutine
  5107. // will call the cancel routine and return the irp.
  5108. //
  5109. status = STATUS_PENDING;
  5110. }
  5111. else
  5112. {
  5113. status = STATUS_CONNECTION_INVALID;
  5114. }
  5115. CTESpinFree(pConnEle,OldIrq2);
  5116. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5117. return(status);
  5118. }
  5119. else
  5120. {
  5121. if (pLowerConn)
  5122. {
  5123. if (pConnEle->state > NBT_ASSOCIATED)
  5124. {
  5125. ULONG state = pConnEle->state;
  5126. tDGRAM_SEND_TRACKING *pTracker;
  5127. pTracker = (tDGRAM_SEND_TRACKING *)pConnEle->pIrpRcv;
  5128. switch (state)
  5129. {
  5130. case NBT_RECONNECTING:
  5131. {
  5132. //
  5133. // the connection is waiting on the Exworker Q to run
  5134. // nbtreconnect. When that runs the connect irp is
  5135. // returned.
  5136. //
  5137. pTracker->Flags |= TRACKER_CANCELLED;
  5138. CTESpinFree(pConnEle,OldIrq2);
  5139. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5140. CTESpinLock(pConnEle,OldIrq);
  5141. FreeRcvBuffers(pConnEle,&OldIrq);
  5142. CTESpinFree(pConnEle,OldIrq);
  5143. return(STATUS_SUCCESS);
  5144. }
  5145. case NBT_SESSION_OUTBOUND:
  5146. {
  5147. tTIMERQENTRY *pTimerEntry;
  5148. LOCATION(0x66)
  5149. if (pTimerEntry = pTracker->pTimer)
  5150. {
  5151. COMPLETIONCLIENT ClientRoutine;
  5152. PVOID pContext;
  5153. //
  5154. // the Session Setup Message has been sent
  5155. // so stop the SessionSetup Timer.
  5156. //
  5157. LOCATION(0x67)
  5158. CHECK_PTR(pTracker);
  5159. pTracker->pTimer = NULL;
  5160. CTESpinFree(pConnEle,OldIrq2);
  5161. StopTimer(pTimerEntry,&ClientRoutine,&pContext);
  5162. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5163. if (ClientRoutine)
  5164. {
  5165. (* ClientRoutine) (pContext, STATUS_CANCELLED);
  5166. }
  5167. // else...
  5168. // the timer has completed and called QueueCleanup
  5169. // so all we need to do is return here.
  5170. }
  5171. else
  5172. {
  5173. ASSERTMSG("Nbt:In outbound state, but no timer.../n",0);
  5174. pTracker->Flags |= TRACKER_CANCELLED;
  5175. CTESpinFree(pConnEle,OldIrq2);
  5176. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5177. }
  5178. return(STATUS_SUCCESS);
  5179. }
  5180. case NBT_CONNECTING:
  5181. {
  5182. //
  5183. // This searchs for timers outstanding on name queries
  5184. // and name queries held up on Lmhosts or Dns Qs
  5185. //
  5186. LOCATION(0x69)
  5187. status = CleanupConnectingState(pConnEle,pLowerConn->pDeviceContext,&OldIrq2,&OldIrq);
  5188. if (status == STATUS_UNSUCCESSFUL)
  5189. {
  5190. LOCATION(0x6A)
  5191. //
  5192. // set this flag to tell sessionsetupcontinue or
  5193. // SessionStartupContinue not to process
  5194. // anything, except to free the tracker
  5195. //
  5196. pTracker->Flags = TRACKER_CANCELLED;
  5197. //
  5198. // failed to cancel the name query so do not deref
  5199. // pConnEle yet.
  5200. //
  5201. //
  5202. // hold on to disconnect irp here - till name query is done
  5203. // then complete both the connect and disconnect irp
  5204. //
  5205. if (pIrpDisc)
  5206. {
  5207. status = STATUS_CONNECTION_INVALID;
  5208. }
  5209. else
  5210. {
  5211. pConnEle->pIrpDisc = pIrp;
  5212. }
  5213. status = STATUS_PENDING;
  5214. ASSERT (NULL != pIrp);
  5215. }
  5216. else if (status == STATUS_PENDING)
  5217. {
  5218. LOCATION(0x6B)
  5219. // the connection is being setup with the transport
  5220. // so disconnect below
  5221. //
  5222. pTracker->Flags = TRACKER_CANCELLED;
  5223. //
  5224. // DelayedCleanupAfterDisconnect expects this ref count
  5225. // to be 2, meaning that it got connected, so increment
  5226. // here
  5227. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  5228. break;
  5229. }
  5230. CTESpinFree(pConnEle,OldIrq2);
  5231. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5232. return(status);
  5233. }
  5234. } // switch
  5235. CTESpinLock(pLowerConn,OldIrq3);
  5236. if (pConnEle->state != NBT_SESSION_UP)
  5237. { //
  5238. // do an abortive disconnect to be sure it completes now.
  5239. //
  5240. Flags = TDI_DISCONNECT_ABORT;
  5241. }
  5242. LOCATION(0x6C)
  5243. IF_DBG(NBT_DEBUG_NAMESRV)
  5244. KdPrint(("Nbt.NbtDisconnect: LowerConn,state %X,Src %X %X\n",
  5245. pLowerConn->State,pLowerConn->SrcIpAddr,pLowerConn));
  5246. ASSERT(pConnEle->RefCount > 1);
  5247. Originator = pLowerConn->bOriginator;
  5248. //
  5249. // the upper connection is going to be put back on its free
  5250. // list, and the lower one is going to get a Disconnect
  5251. // request, so put the upper back in associated, and separate
  5252. // the upper and lower connections
  5253. //
  5254. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  5255. CHECK_PTR(pConnEle);
  5256. CHECK_PTR(pLowerConn);
  5257. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  5258. LowerState = pLowerConn->State;
  5259. StateRcv = pLowerConn->StateRcv;
  5260. //
  5261. // if we had a connection in partial rcv state, make sure to remove it from
  5262. // the list
  5263. //
  5264. #ifdef VXD
  5265. if ((pLowerConn->StateRcv == PARTIAL_RCV) &&
  5266. (pLowerConn->fOnPartialRcvList == TRUE))
  5267. {
  5268. RemoveEntryList (&pLowerConn->PartialRcvList);
  5269. pLowerConn->fOnPartialRcvList = FALSE;
  5270. InitializeListHead(&pLowerConn->PartialRcvList);
  5271. }
  5272. #endif
  5273. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTING);
  5274. pLowerConn->bDisconnectIrpPendingInTCP = TRUE;
  5275. SetStateProc (pLowerConn, RejectAnyData);
  5276. if (!pConnEle->pIrpDisc)
  5277. {
  5278. pLowerConn->pIrp = pIrp ;
  5279. }
  5280. CTESpinFree(pLowerConn,OldIrq3);
  5281. PUSH_LOCATION(0x84);
  5282. CTESpinFree(pConnEle,OldIrq2);
  5283. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5284. // remove the reference added to pConnEle when pLowerConn pointed
  5285. // to it, since that pointer link was just removed.
  5286. // if the state is not disconnecting...
  5287. //
  5288. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  5289. RelistIt = TRUE;
  5290. }
  5291. else
  5292. {
  5293. LOCATION(0x6D)
  5294. PUSH_LOCATION(0x83);
  5295. CHECK_PTR(pConnEle);
  5296. CHECK_PTR(pLowerConn);
  5297. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  5298. StateRcv = NORMAL;
  5299. CTESpinFree(pConnEle,OldIrq2);
  5300. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5301. }
  5302. //
  5303. // check for any RcvIrp that may be still around
  5304. //
  5305. CTESpinLock(pLowerConn,OldIrq);
  5306. if (StateRcv == FILL_IRP)
  5307. {
  5308. if (pConnEle->pIrpRcv)
  5309. {
  5310. PCTE_IRP pIrp;
  5311. IF_DBG(NBT_DEBUG_DISCONNECT)
  5312. KdPrint(("Nbt.NbtDisconnect: Cancelling RcvIrp on Disconnect!!!\n"));
  5313. pIrp = pConnEle->pIrpRcv;
  5314. CHECK_PTR(pConnEle);
  5315. pConnEle->pIrpRcv = NULL;
  5316. CTESpinFree(pLowerConn,OldIrq);
  5317. #ifndef VXD
  5318. IoCancelIrp(pIrp);
  5319. #else
  5320. CTEIoComplete(pIrp,STATUS_CANCELLED,0);
  5321. #endif
  5322. CHECK_PTR(pConnEle);
  5323. pConnEle->pIrpRcv = NULL;
  5324. }
  5325. else
  5326. {
  5327. CTESpinFree(pLowerConn,OldIrq);
  5328. }
  5329. //
  5330. // when the disconnect irp is returned we will close the connection
  5331. // to avoid any peculiarities. This also lets the other side
  5332. // know that we did not get all the data.
  5333. //
  5334. Flags = TDI_DISCONNECT_ABORT;
  5335. }
  5336. else
  5337. {
  5338. CTESpinFree(pLowerConn,OldIrq);
  5339. }
  5340. //
  5341. // check if there is still data waiting in the transport for this end point
  5342. // and if so do an abortive disconnect to let the other side know that something
  5343. // went wrong
  5344. //
  5345. if (pConnEle->BytesInXport)
  5346. {
  5347. PUSH_LOCATION(0xA0);
  5348. IF_DBG(NBT_DEBUG_DISCONNECT)
  5349. KdPrint(("Nbt.NbtDisconnect: Doing ABORTIVE disconnect, dataInXport = %X\n",
  5350. pConnEle->BytesInXport));
  5351. Flags = TDI_DISCONNECT_ABORT;
  5352. }
  5353. }
  5354. else
  5355. {
  5356. CTESpinFree(pConnEle,OldIrq2);
  5357. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5358. }
  5359. }
  5360. ASSERT(pConnEle->RefCount > 0);
  5361. CTESpinLock (pConnEle,OldIrq);
  5362. FreeRcvBuffers (pConnEle,&OldIrq);
  5363. CTESpinFree (pConnEle,OldIrq);
  5364. if (RelistIt)
  5365. {
  5366. //
  5367. // put the upper connection back on its free list
  5368. //
  5369. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  5370. RelistConnection (pConnEle);
  5371. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5372. }
  5373. //
  5374. // disconnect (and delete) the lower connection
  5375. //
  5376. // when nbtdisconnect is called from cleanup connection it does not
  5377. // have an irp and it wants a synchronous disconnect, so set wait
  5378. // to true in this case
  5379. //
  5380. if (!pIrp)
  5381. {
  5382. Wait = TRUE;
  5383. }
  5384. else
  5385. {
  5386. Wait = FALSE;
  5387. }
  5388. status = DisconnectLower(pLowerConn,LowerState,Flags,pTimeout,Wait);
  5389. ASSERT (!Wait || STATUS_PENDING != status);
  5390. if ((pConnEle->pIrpDisc) &&
  5391. (status != STATUS_INSUFFICIENT_RESOURCES))
  5392. {
  5393. // don't complete the disconnect irp yet if we are holding onto
  5394. // it
  5395. status = STATUS_PENDING;
  5396. }
  5397. return(status);
  5398. }
  5399. //----------------------------------------------------------------------------
  5400. NTSTATUS
  5401. DisconnectLower(
  5402. IN tLOWERCONNECTION *pLowerConn,
  5403. IN ULONG state,
  5404. IN ULONG Flags,
  5405. IN PVOID Timeout,
  5406. IN BOOLEAN Wait
  5407. )
  5408. /*++
  5409. Routine Description:
  5410. This Routine handles disconnecting the lower half of a connection.
  5411. Arguments:
  5412. Return Value:
  5413. NTSTATUS - status of the request
  5414. --*/
  5415. {
  5416. NTSTATUS status=STATUS_SUCCESS;
  5417. tDGRAM_SEND_TRACKING *pTracker;
  5418. if (pLowerConn)
  5419. {
  5420. //
  5421. // no need to disconnect a connection in the connecting state since it
  5422. // hasn't connected yet...i.e. one where the destination refuses to
  5423. // accept the tcp connection.... hmmmm maybe we do need to disconnect
  5424. // a connection in the connecting state, since the transport is
  5425. // actively trying to connect the connection, and we need to stop
  5426. // that activity - so the Upper connection is connecting during
  5427. // name resolution, but the lower one isn't connecting until the
  5428. // tcp connection phase begins.
  5429. //
  5430. if ((state >= NBT_CONNECTING) && (state <= NBT_SESSION_UP))
  5431. {
  5432. //
  5433. // got a cleanup for an active connection, so send a disconnect down
  5434. // to the transport
  5435. //
  5436. IF_DBG(NBT_DEBUG_DISCONNECT)
  5437. KdPrint(("Nbt.DisconnectLower: Waiting for disconnect...\n"));
  5438. status = GetTracker(&pTracker, NBT_TRACKER_DISCONNECT_LOWER);
  5439. if (NT_SUCCESS(status))
  5440. {
  5441. ULONG TimeVal;
  5442. // this should return status pending and the irp will be completed
  5443. // in DelayedCleanupAfterDisconnect in hndlrs.c
  5444. pTracker->pConnEle = (PVOID)pLowerConn;
  5445. #if DBG
  5446. if (Timeout)
  5447. {
  5448. TimeVal = ((PTIME)Timeout)->LowTime;
  5449. }
  5450. else
  5451. {
  5452. TimeVal = 0;
  5453. }
  5454. IF_DBG(NBT_DEBUG_DISCONNECT)
  5455. KdPrint(("Nbt.DisconnectLower: Disconnect Timout = %X,Flags=%X\n",
  5456. TimeVal,Flags));
  5457. #endif
  5458. // in the case where CleanupAddress calls cleanupConnection
  5459. // which calls nbtdisconnect, we do not have an irp to wait
  5460. // on so pass a flag down to TdiDisconnect to do a synchronous
  5461. // disconnect.
  5462. //
  5463. status = TcpDisconnect (pTracker, Timeout, Flags, Wait);
  5464. #ifndef VXD
  5465. if (Wait)
  5466. {
  5467. // we need to call disconnect done now
  5468. // to free the tracker and cleanup the connection
  5469. //
  5470. DisconnectDone(pTracker,status,0);
  5471. }
  5472. #else
  5473. //
  5474. // if the disconnect is abortive, transport doesn't call us
  5475. // back so let's call DisconnectDone so that the lowerconn gets
  5476. // cleaned up properly! (Wait parm is of no use in vxd)
  5477. //
  5478. if (Flags == TDI_DISCONNECT_ABORT)
  5479. {
  5480. // we need to call disconnect done now
  5481. // to free the tracker and cleanup the connection
  5482. //
  5483. DisconnectDone(pTracker,STATUS_SUCCESS,0);
  5484. }
  5485. #endif
  5486. }
  5487. else
  5488. {
  5489. status = STATUS_INSUFFICIENT_RESOURCES;
  5490. }
  5491. }
  5492. }
  5493. return status ;
  5494. }
  5495. //----------------------------------------------------------------------------
  5496. NTSTATUS
  5497. NbtAccept(
  5498. TDI_REQUEST *pRequest,
  5499. IN TDI_CONNECTION_INFORMATION *pAcceptInfo,
  5500. OUT TDI_CONNECTION_INFORMATION *pReturnAcceptInfo,
  5501. IN PIRP pIrp)
  5502. /*++
  5503. Routine Description
  5504. This routine handles accepting an inbound connection by a client.
  5505. The client calls this routine after it has been alerted
  5506. by a Listen completing back to the client.
  5507. Arguments:
  5508. Return Values:
  5509. TDI_STATUS - status of the request
  5510. --*/
  5511. {
  5512. tCONNECTELE *pConnectEle;
  5513. NTSTATUS status;
  5514. CTELockHandle OldIrq;
  5515. // get the client object associated with this connection
  5516. pConnectEle = (tCONNECTELE *)pRequest->Handle.ConnectionContext;
  5517. CTEVerifyHandle(pConnectEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
  5518. //
  5519. // a Listen has completed
  5520. //
  5521. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  5522. CTESpinLockAtDpc(pConnectEle);
  5523. if (pConnectEle->state == NBT_SESSION_WAITACCEPT)
  5524. {
  5525. tLOWERCONNECTION *pLowerConn;
  5526. //
  5527. // We need to send a session response PDU here, since a Listen has
  5528. // has completed back to the client, and the session is not yet up
  5529. //
  5530. SET_STATE_UPPER (pConnectEle, NBT_SESSION_UP);
  5531. pLowerConn = (tLOWERCONNECTION *)pConnectEle->pLowerConnId;
  5532. SET_STATE_LOWER (pLowerConn, NBT_SESSION_UP);
  5533. SET_STATERCV_LOWER(pLowerConn, NORMAL, Normal);
  5534. CTESpinFreeAtDpc(pConnectEle);
  5535. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5536. status = TcpSendSessionResponse(
  5537. pLowerConn,
  5538. NBT_POSITIVE_SESSION_RESPONSE,
  5539. 0L);
  5540. if (NT_SUCCESS(status))
  5541. {
  5542. status = STATUS_SUCCESS;
  5543. }
  5544. }
  5545. else
  5546. {
  5547. status = STATUS_UNSUCCESSFUL;
  5548. CTESpinFreeAtDpc(pConnectEle);
  5549. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5550. }
  5551. return(status);
  5552. }
  5553. //----------------------------------------------------------------------------
  5554. NTSTATUS
  5555. NbtReceiveDatagram(
  5556. IN TDI_REQUEST *pRequest,
  5557. IN PTDI_CONNECTION_INFORMATION pReceiveInfo,
  5558. IN PTDI_CONNECTION_INFORMATION pReturnedInfo,
  5559. IN LONG ReceiveLength,
  5560. IN LONG *pReceivedLength,
  5561. IN PVOID pBuffer,
  5562. IN tDEVICECONTEXT *pDeviceContext,
  5563. IN PIRP pIrp
  5564. )
  5565. /*++
  5566. Routine Description
  5567. This routine handles sending client data to the Transport TDI
  5568. interface. It is mostly a pass through routine for the data
  5569. except that this code must create a datagram header and pass that
  5570. header back to the calling routine.
  5571. Arguments:
  5572. Return Values:
  5573. NTSTATUS - status of the request
  5574. --*/
  5575. {
  5576. NTSTATUS status;
  5577. tCLIENTELE *pClientEle;
  5578. CTELockHandle OldIrq;
  5579. tRCVELE *pRcvEle;
  5580. tADDRESSELE *pAddressEle;
  5581. pClientEle = (tCLIENTELE *)pRequest->Handle.AddressHandle;
  5582. CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
  5583. pAddressEle = pClientEle->pAddress;
  5584. *pReceivedLength = 0;
  5585. IF_DBG(NBT_DEBUG_NAMESRV)
  5586. KdPrint(("Nbt.NbtReceiveDatagram: RcvDgram posted (pIrp) %X \n",pIrp));
  5587. pRcvEle = (tRCVELE *)NbtAllocMem(sizeof(tRCVELE),NBT_TAG('J'));
  5588. if (!pRcvEle)
  5589. {
  5590. return(STATUS_INSUFFICIENT_RESOURCES);
  5591. }
  5592. pRcvEle->pIrp = pIrp;
  5593. pRcvEle->ReceiveInfo = pReceiveInfo;
  5594. pRcvEle->ReturnedInfo = pReturnedInfo;
  5595. pRcvEle->RcvLength = ReceiveLength;
  5596. pRcvEle->pRcvBuffer = pBuffer;
  5597. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  5598. //
  5599. // tack the receive on to the client element for later use
  5600. //
  5601. InsertTailList(&pClientEle->RcvDgramHead,&pRcvEle->Linkage);
  5602. status = NTCheckSetCancelRoutine(pIrp,(PVOID)NbtCancelRcvDgram,pDeviceContext);
  5603. if (!NT_SUCCESS(status))
  5604. {
  5605. RemoveEntryList(&pRcvEle->Linkage);
  5606. }
  5607. else
  5608. {
  5609. status = STATUS_PENDING;
  5610. }
  5611. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  5612. return(status);
  5613. }
  5614. //----------------------------------------------------------------------------
  5615. NTSTATUS
  5616. FindNameOrQuery(
  5617. IN PUCHAR pName,
  5618. IN tDEVICECONTEXT *pDeviceContext,
  5619. IN PVOID QueryCompletion,
  5620. IN tDGRAM_SEND_TRACKING *pTracker,
  5621. IN ULONG NameFlags,
  5622. OUT tIPADDRESS *pIpAddress,
  5623. OUT tNAMEADDR **ppNameAddr,
  5624. IN ULONG NameReferenceContext,
  5625. IN BOOLEAN DgramSend
  5626. )
  5627. /*++
  5628. Routine Description
  5629. This routine handles finding a name in the local or remote table or doing
  5630. a name query on the network.
  5631. Arguments:
  5632. Return Values:
  5633. NTSTATUS - status of the request
  5634. --*/
  5635. {
  5636. tNAMEADDR *pNameAddr;
  5637. CTELockHandle OldIrq2;
  5638. NTSTATUS status=STATUS_UNSUCCESSFUL;
  5639. BOOLEAN FoundInLocalTable = FALSE;
  5640. tDEVICECONTEXT *pThisDeviceContext;
  5641. LIST_ENTRY *pHead, *pEntry;
  5642. ULONG Index;
  5643. //
  5644. // this saves the client threads security context so we can
  5645. // open remote lmhost files later.- it is outside the Spin locks
  5646. // so it can be pageable
  5647. //
  5648. CTESaveClientSecurity(pTracker);
  5649. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  5650. pTracker->pTrackerWorker = NULL; // Initialize the NameQuery Tracker
  5651. #ifdef MULTIPLE_WINS
  5652. if (ppNameAddr)
  5653. {
  5654. *ppNameAddr = NULL;
  5655. }
  5656. #endif
  5657. NbtTrace(NBT_TRACE_NAMESRV, ("pTracker %p: %!NBTNAME!<%02x>",
  5658. pTracker,
  5659. pTracker->pDestName,
  5660. pTracker->pDestName[NETBIOS_NAME_SIZE-1]));
  5661. //
  5662. // Fail all connect attempts to 1C names.
  5663. //
  5664. if ((pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c) &&
  5665. (pTracker->Flags & SESSION_SETUP_FLAG))
  5666. {
  5667. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5668. DELETE_CLIENT_SECURITY(pTracker);
  5669. KdPrint(("Nbt.FindNameOrQuery: Session setup -- p1CNameAddr was NULL\n"));
  5670. NbtTrace(NBT_TRACE_NAMESRV, ("pTracker %p: STATUS_UNEXPECTED_NETWORK_ERROR", pTracker));
  5671. return(STATUS_UNEXPECTED_NETWORK_ERROR);
  5672. }
  5673. // send to the NetBios Broadcast name, so use the subnet broadcast
  5674. // address - also - a
  5675. // Kludge to keep the browser happy - always broadcast sends to
  5676. // 1d, however NodeStatus's are sent to the node owning the 1d name now.
  5677. //
  5678. if ((pName[0] == '*') || ((pName[NETBIOS_NAME_SIZE-1] == 0x1d) && (DgramSend)))
  5679. {
  5680. // this 'fake' pNameAddr has to be setup carefully so that the memory
  5681. // is released when NbtDeferenceName is called from SendDgramCompletion
  5682. // Note that this code does not apply to NbtConnect since these names
  5683. // are group names, and NbtConnect will not allow a session to a group
  5684. // name.
  5685. status = STATUS_INSUFFICIENT_RESOURCES ;
  5686. if (pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('K')))
  5687. {
  5688. CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
  5689. CTEMemCopy( pNameAddr->Name, pName, NETBIOS_NAME_SIZE ) ;
  5690. pNameAddr->IpAddress = pDeviceContext->BroadcastAddress;
  5691. pNameAddr->NameTypeState = NAMETYPE_GROUP | STATE_RESOLVED;
  5692. // gets incremented below, and decremented when NBT_DEREFERENCE_NAMEADDR
  5693. // is called
  5694. CHECK_PTR(pNameAddr);
  5695. pNameAddr->RefCount = 0;
  5696. pNameAddr->Verify = LOCAL_NAME;
  5697. pNameAddr->AdapterMask = pDeviceContext->AdapterMask;
  5698. pNameAddr->ReleaseMask = (CTEULONGLONG) 0;
  5699. // adjust the linked list ptr to fool the RemoveEntry routine
  5700. // so it does not do anything wierd in NbtDeferenceName
  5701. //
  5702. pNameAddr->Linkage.Flink = pNameAddr->Linkage.Blink = &pNameAddr->Linkage;
  5703. status = STATUS_SUCCESS;
  5704. }
  5705. else
  5706. {
  5707. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5708. DELETE_CLIENT_SECURITY(pTracker);
  5709. NbtTrace(NBT_TRACE_NAMESRV, ("pTracker %p: STATUS_INSUFFICIENT_RESOURCES", pTracker));
  5710. return(STATUS_INSUFFICIENT_RESOURCES);
  5711. }
  5712. }
  5713. else
  5714. {
  5715. // The pdu is all made up and ready to go except that we don't know
  5716. // the destination IP address yet, so check in the local then remote
  5717. // table for the ip address.
  5718. //
  5719. pNameAddr = NULL;
  5720. //
  5721. // Dont check local cache for 1C names, to force a WINS query; so we find other
  5722. // DCs even if we have a local DC running.
  5723. //
  5724. if ((pName[NETBIOS_NAME_SIZE-1] != 0x1c) )
  5725. {
  5726. status = FindInHashTable (NbtConfig.pLocalHashTbl, pName, NbtConfig.pScope, &pNameAddr);
  5727. }
  5728. else
  5729. {
  5730. status = STATUS_UNSUCCESSFUL;
  5731. }
  5732. // check the remote table now if not found, or if it was found in
  5733. // conflict in the local table, or if it was found and its a group name
  5734. // or if it was found to be resolving in the local table. When the
  5735. // remote query timesout, it will check the local again to see if
  5736. // it is resolved yet.
  5737. // Going to the remote table for group names
  5738. // allows special Internet group names to be registered as
  5739. // as group names in the local table and still prompt this code to go
  5740. // to the name server to check for an internet group name. Bnodes do
  5741. // not understand internet group names as being different from
  5742. // regular group names, - they just broadcast to both. (Note: this
  5743. // allows Bnodes to resolve group names in the local table and do
  5744. // a broadcast to them without a costly broadcast name query for a
  5745. // group name (where everyone responds)). Node Status uses this routine too
  5746. // and it always wants to find the singular address of the destination,
  5747. // since it doesn't make sense doing a node status to the broadcast
  5748. // address.
  5749. // DgramSend is a flag to differentiate Connect attempts from datagram
  5750. // send attempts, so the last part of the If says that if it is a
  5751. // group name and not a Bnode, and not a Dgram Send, then check the
  5752. // remote table.
  5753. //
  5754. if ((!NT_SUCCESS(status)) ||
  5755. (pNameAddr->NameTypeState & STATE_CONFLICT) ||
  5756. (pNameAddr->NameTypeState & STATE_RESOLVING))
  5757. {
  5758. pNameAddr = NULL;
  5759. status = FindInHashTable (NbtConfig.pRemoteHashTbl, pName, NbtConfig.pScope, &pNameAddr);
  5760. if (NT_SUCCESS(status) &&
  5761. NbtConfig.SmbDisableNetbiosNameCacheLookup &&
  5762. IsDeviceNetbiosless(pDeviceContext) &&
  5763. !(pNameAddr->NameTypeState & PRELOADED) &&
  5764. NULL == pNameAddr->FQDN.Buffer) {
  5765. status = STATUS_UNSUCCESSFUL;
  5766. }
  5767. //
  5768. // See if we have an address resolved on this device
  5769. //
  5770. if (NT_SUCCESS(status))
  5771. {
  5772. ASSERT (!(pNameAddr->NameTypeState & STATE_RELEASED));
  5773. status = PickBestAddress (pNameAddr, pDeviceContext, pIpAddress);
  5774. }
  5775. }
  5776. else if (((IsDeviceNetbiosless (pDeviceContext)) &&
  5777. (pNameAddr->NameFlags & NAME_REGISTERED_ON_SMBDEV)) ||
  5778. ((!IsDeviceNetbiosless(pDeviceContext)) &&
  5779. ((pDeviceContext->IpAddress) &&
  5780. (pNameAddr->AdapterMask & pDeviceContext->AdapterMask))))
  5781. {
  5782. FoundInLocalTable = TRUE;
  5783. *pIpAddress = pDeviceContext->IpAddress;
  5784. pNameAddr->IpAddress = pDeviceContext->IpAddress;
  5785. }
  5786. else
  5787. {
  5788. //
  5789. // This is a Local name, so find the first device this name is registered on
  5790. //
  5791. if (!IsDeviceNetbiosless (pDeviceContext)) {
  5792. pHead = pEntry = &NbtConfig.DeviceContexts;
  5793. while ((pEntry = pEntry->Flink) != pHead)
  5794. {
  5795. pThisDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  5796. if ((pThisDeviceContext->IpAddress) &&
  5797. (pThisDeviceContext->AdapterMask & pNameAddr->AdapterMask))
  5798. {
  5799. pNameAddr->IpAddress = pThisDeviceContext->IpAddress;
  5800. *pIpAddress = pThisDeviceContext->IpAddress;
  5801. FoundInLocalTable = TRUE;
  5802. break;
  5803. }
  5804. }
  5805. }
  5806. /*
  5807. * The name is in local name table. However, we cannot find a device which has an IP address.
  5808. */
  5809. if (!FoundInLocalTable) {
  5810. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5811. DELETE_CLIENT_SECURITY(pTracker);
  5812. NbtTrace(NBT_TRACE_NAMESRV, ("pTracker %p: STATUS_BAD_NETWORK_PATH", pTracker));
  5813. return STATUS_BAD_NETWORK_PATH;
  5814. }
  5815. }
  5816. //
  5817. // If we found the name, but the name does not match
  5818. // what we were looking for, return error!
  5819. //
  5820. if ((status == STATUS_SUCCESS) &&
  5821. (!(pNameAddr->NameTypeState & NameFlags)))
  5822. {
  5823. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5824. DELETE_CLIENT_SECURITY(pTracker);
  5825. KdPrint(("Nbt.FindNameOrQuery: NameFlags=<%x> != pNameAddr->NameTypeState=<%x>\n",
  5826. NameFlags, pNameAddr->NameTypeState));
  5827. NbtTrace(NBT_TRACE_NAMESRV, ("pTracker %p: STATUS_UNEXPECTED_NETWORK_ERROR", pTracker));
  5828. return(STATUS_UNEXPECTED_NETWORK_ERROR);
  5829. }
  5830. }
  5831. // The proxy puts name in the released state, so we need to ignore those
  5832. // and do another name query
  5833. // If the name is not resolved on this adapter then do a name query.
  5834. //
  5835. // MAlam: 2/4/97
  5836. // Added fix for Local Cluster Name Resolution: If the name is in the Local
  5837. // Names Cache, we do not need to check the adapter it's registered on. This
  5838. // is mainly to facilitate names registered on pseudo-devices which have to
  5839. // be made visible locally.
  5840. //
  5841. if (!NT_SUCCESS(status))
  5842. {
  5843. // fill in some tracking values so we can complete the send later
  5844. InitializeListHead(&pTracker->TrackerList);
  5845. #if _NETBIOSLESS
  5846. // Query on the Net only if this request is not on a Netbiosless Device
  5847. if (IsDeviceNetbiosless(pDeviceContext))
  5848. {
  5849. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5850. status = STATUS_UNSUCCESSFUL;
  5851. }
  5852. else
  5853. #endif
  5854. {
  5855. // this will query the name on the network and call a routine to
  5856. // finish sending the datagram when the query completes.
  5857. status = QueryNameOnNet (pName,
  5858. NbtConfig.pScope,
  5859. NBT_UNIQUE, //use this as the default
  5860. pTracker,
  5861. QueryCompletion,
  5862. NodeType & NODE_MASK,
  5863. NULL,
  5864. pDeviceContext,
  5865. &OldIrq2);
  5866. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5867. }
  5868. }
  5869. else
  5870. {
  5871. // check the name state and if resolved, send to it
  5872. if (pNameAddr->NameTypeState & STATE_RESOLVED)
  5873. {
  5874. //
  5875. // found the name in the remote hash table, so send to it
  5876. //
  5877. // increment refcount so the name does not disappear out from under us
  5878. NBT_REFERENCE_NAMEADDR (pNameAddr, NameReferenceContext);
  5879. if (DgramSend)
  5880. {
  5881. pTracker->p1CNameAddr = NULL;
  5882. //
  5883. // check if it is a 1C name and if there is a name in
  5884. // the domainname list
  5885. //
  5886. if (pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c)
  5887. {
  5888. //
  5889. // If the 1CNameAddr field is NULL here, we overwrite the pConnEle element (which is
  5890. // a union in the tracker). We check for NULL here and fail the request.
  5891. //
  5892. if (pTracker->p1CNameAddr = FindInDomainList(pTracker->pDestName,&DomainNames.DomainList))
  5893. {
  5894. NBT_REFERENCE_NAMEADDR (pTracker->p1CNameAddr, NameReferenceContext);
  5895. }
  5896. }
  5897. }
  5898. //
  5899. // overwrite the pDestName field with the pNameAddr value
  5900. // so that SendDgramContinue can send to Internet group names
  5901. //
  5902. pTracker->pNameAddr = pNameAddr;
  5903. if (ppNameAddr)
  5904. {
  5905. *ppNameAddr = pNameAddr;
  5906. }
  5907. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5908. }
  5909. else if (pNameAddr->NameTypeState & STATE_RESOLVING)
  5910. {
  5911. ASSERTMSG("A resolving name in the name table!",0);
  5912. status = SendToResolvingName(pNameAddr,
  5913. pName,
  5914. OldIrq2,
  5915. pTracker,
  5916. QueryCompletion);
  5917. }
  5918. else
  5919. {
  5920. //
  5921. // Name neither in the RESOLVED nor RESOLVING state
  5922. //
  5923. NBT_PROXY_DBG(("FindNameOrQuery: STATE of NAME %16.16s(%X) is %d\n",
  5924. pName, pName[15], pNameAddr->NameTypeState & NAME_STATE_MASK));
  5925. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  5926. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  5927. }
  5928. }
  5929. if (status != STATUS_PENDING)
  5930. {
  5931. DELETE_CLIENT_SECURITY(pTracker);
  5932. NbtTrace(NBT_TRACE_NAMESRV, ("pTracker %p: %!status!", pTracker, status));
  5933. }
  5934. return(status);
  5935. }
  5936. //----------------------------------------------------------------------------
  5937. tNAMEADDR *
  5938. FindNameRemoteThenLocal(
  5939. IN tDGRAM_SEND_TRACKING *pTracker,
  5940. OUT tIPADDRESS *pIpAddress,
  5941. OUT PULONG plNameType
  5942. )
  5943. /*++
  5944. Routine Description
  5945. This routine Queries the remote hash table then the local one for a name.
  5946. Arguments:
  5947. Return Values:
  5948. NTSTATUS - completion status
  5949. --*/
  5950. {
  5951. tNAMEADDR *pNameAddr;
  5952. tIPADDRESS IpAddress = 0;
  5953. tIPADDRESS *pIpNbtGroupList = NULL;
  5954. if (pNameAddr = FindName (NBT_REMOTE, pTracker->pDestName, NbtConfig.pScope, plNameType)) {
  5955. pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
  5956. } else {
  5957. pNameAddr = FindName (NBT_LOCAL, pTracker->pDestName, NbtConfig.pScope, plNameType);
  5958. }
  5959. if ((pNameAddr) &&
  5960. (!NT_SUCCESS (PickBestAddress (pNameAddr, pTracker->pDeviceContext, &IpAddress))))
  5961. {
  5962. pNameAddr = NULL;
  5963. }
  5964. if (pIpAddress)
  5965. {
  5966. *pIpAddress = IpAddress;
  5967. }
  5968. return(pNameAddr);
  5969. }
  5970. //----------------------------------------------------------------------------
  5971. NTSTATUS
  5972. SendToResolvingName(
  5973. IN tNAMEADDR *pNameAddr,
  5974. IN PCHAR pName,
  5975. IN CTELockHandle OldIrq,
  5976. IN tDGRAM_SEND_TRACKING *pTracker,
  5977. IN PVOID QueryCompletion
  5978. )
  5979. /*++
  5980. Routine Description
  5981. This routine handles the situation where a session send or a datagram send
  5982. is made WHILE the name is still resolving. The idea here is to hook this
  5983. tracker on to the one already doing the name query and when the first completes
  5984. this tracker will be completed too.
  5985. Arguments:
  5986. Return Values:
  5987. NTSTATUS - completion status
  5988. --*/
  5989. {
  5990. tDGRAM_SEND_TRACKING *pTrack;
  5991. tTIMERQENTRY *pTimer;
  5992. KdPrint(("Nbt.SendToResolvingName: Two Name Queries for the same Resolving name %15.15s <%X>\n",
  5993. pNameAddr->Name,pNameAddr->Name[NETBIOS_NAME_SIZE-1]));
  5994. #ifdef PROXY_NODE
  5995. //
  5996. // Check if the query outstanding was sent by the PROXY code.
  5997. // If yes, we stop the timer and send the query ourselves.
  5998. //
  5999. if (pNameAddr->ProxyReqType != NAMEREQ_REGULAR)
  6000. {
  6001. NTSTATUS status;
  6002. //
  6003. // Stop the proxy timer. This will result in
  6004. // cleanup of the tracker buffer
  6005. //
  6006. NBT_PROXY_DBG(("SendToResolvingName: STOPPING PROXY TIMER FOR NAME %16.16s(%X)\n", pName, pName[15]));
  6007. // **** TODO ****** the name may be resolving with LMhosts or
  6008. // DNS so we can't just stop the timer and carry on!!!.
  6009. //
  6010. CHECK_PTR(pNameAddr);
  6011. if (pTimer = pNameAddr->pTimer)
  6012. {
  6013. pNameAddr->pTimer = NULL;
  6014. status = StopTimer(pTimer,NULL,NULL);
  6015. }
  6016. pNameAddr->NameTypeState = STATE_RELEASED;
  6017. //
  6018. // this will query the name on the network and call a
  6019. // routine to finish sending the datagram when the query
  6020. // completes.
  6021. //
  6022. status = QueryNameOnNet (pName,
  6023. NbtConfig.pScope,
  6024. NBT_UNIQUE, //use this as the default
  6025. pTracker,
  6026. QueryCompletion,
  6027. NodeType & NODE_MASK,
  6028. pNameAddr,
  6029. pTracker->pDeviceContext,
  6030. &OldIrq);
  6031. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6032. return(status);
  6033. //
  6034. // NOTE: QueryNameOnNet frees the pNameAddr by calling NBT_DEREFERENCE_NAMEADDR
  6035. // if that routine fails for some reason.
  6036. //
  6037. }
  6038. else
  6039. #endif
  6040. {
  6041. ASSERT(pNameAddr->pTracker);
  6042. // there is currently a name query outstanding so just hook
  6043. // our tracker to the tracker already there.. use the
  6044. // list entry TrackerList for this.
  6045. //
  6046. pTrack = pNameAddr->pTracker;
  6047. //
  6048. // save the completion routine for this tracker since it may
  6049. // be different than the tracker currently doing the query
  6050. //
  6051. pTracker->CompletionRoutine = QueryCompletion;
  6052. InsertTailList(&pTrack->TrackerList,&pTracker->TrackerList);
  6053. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6054. // we don't want to complete the Irp, so return pending status
  6055. //
  6056. return(STATUS_PENDING);
  6057. }
  6058. }
  6059. //----------------------------------------------------------------------------
  6060. extern
  6061. USHORT
  6062. GetTransactId(
  6063. )
  6064. /*++
  6065. Routine Description:
  6066. This Routine increments the transaction id with the spin lock held.
  6067. It uses NbtConfig.JointLock.
  6068. Arguments:
  6069. Return Value:
  6070. --*/
  6071. {
  6072. USHORT TransactId;
  6073. CTELockHandle OldIrq;
  6074. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6075. TransactId = NbtConfig.TransactionId++;
  6076. #ifndef VXD
  6077. if (TransactId == 0xFFFF)
  6078. {
  6079. NbtConfig.TransactionId = WINS_MAXIMUM_TRANSACTION_ID +1;
  6080. }
  6081. #else
  6082. if (TransactId == (DIRECT_DNS_NAME_QUERY_BASE - 1))
  6083. {
  6084. NbtConfig.TransactionId = 0;
  6085. }
  6086. #endif
  6087. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6088. return (TransactId);
  6089. }
  6090. //----------------------------------------------------------------------------
  6091. extern
  6092. VOID
  6093. CTECountedAllocMem(
  6094. PVOID *pBuffer,
  6095. ULONG Size
  6096. )
  6097. /*++
  6098. Routine Description:
  6099. This Routine allocates memory and counts the amount allocated so that it
  6100. will not allocate too much - generally this is used in datagram sends
  6101. where the send datagram is buffered.
  6102. Arguments:
  6103. Size - the number of bytes to allocate
  6104. PVOID - a pointer to the memory or NULL if a failure
  6105. Return Value:
  6106. --*/
  6107. {
  6108. CTELockHandle OldIrq;
  6109. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6110. if (NbtMemoryAllocated > NbtConfig.MaxDgramBuffering)
  6111. {
  6112. *pBuffer = NULL;
  6113. }
  6114. else
  6115. {
  6116. NbtMemoryAllocated += Size;
  6117. *pBuffer = NbtAllocMem(Size,NBT_TAG('L'));
  6118. }
  6119. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6120. }
  6121. //----------------------------------------------------------------------------
  6122. extern
  6123. VOID
  6124. CTECountedFreeMem(
  6125. PVOID pBuffer,
  6126. ULONG Size,
  6127. BOOLEAN fJointLockHeld
  6128. )
  6129. /*++
  6130. Routine Description:
  6131. This Routine frees memory and decrements the global count of acquired
  6132. memory.
  6133. Arguments:
  6134. PVOID - a pointer to the memory to free
  6135. Size - the number of bytes to free
  6136. Return Value:
  6137. --*/
  6138. {
  6139. CTELockHandle OldIrq;
  6140. if (!fJointLockHeld)
  6141. {
  6142. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6143. }
  6144. ASSERT(NbtMemoryAllocated >= Size);
  6145. if (NbtMemoryAllocated >= Size)
  6146. {
  6147. NbtMemoryAllocated -= Size;
  6148. }
  6149. else
  6150. {
  6151. NbtMemoryAllocated = 0;
  6152. }
  6153. if (!fJointLockHeld)
  6154. {
  6155. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6156. }
  6157. CTEMemFree(pBuffer);
  6158. }
  6159. //----------------------------------------------------------------------------
  6160. NTSTATUS
  6161. BuildSendDgramHdr(
  6162. IN ULONG SendLength,
  6163. IN tDEVICECONTEXT *pDeviceContext,
  6164. IN PCHAR pSourceName,
  6165. IN PCHAR pDestName,
  6166. IN ULONG NameLength,
  6167. IN PVOID pBuffer,
  6168. OUT tDGRAMHDR **ppDgramHdr,
  6169. OUT tDGRAM_SEND_TRACKING **ppTracker
  6170. )
  6171. /*++
  6172. Routine Description
  6173. This routine builds a datagram header necessary for sending datagrams.
  6174. It include the to and from Netbios names and ip addresses.
  6175. Arguments:
  6176. pContext - ptr to the DGRAM_TRACKER block
  6177. NTSTATUS - completion status
  6178. Return Values:
  6179. VOID
  6180. --*/
  6181. {
  6182. NTSTATUS status;
  6183. PCHAR pCopyTo;
  6184. tDGRAM_SEND_TRACKING *pTracker;
  6185. tDGRAMHDR *pDgramHdr;
  6186. ULONG HdrLength;
  6187. ULONG HLength;
  6188. ULONG TotalLength;
  6189. PVOID pSendBuffer;
  6190. PVOID pNameBuffer;
  6191. ULONG BytesCopied;
  6192. USHORT TransactId;
  6193. CTEPagedCode();
  6194. HdrLength = DGRAM_HDR_SIZE + (NbtConfig.ScopeLength <<1);
  6195. HLength = ((HdrLength + 3) / 4 ) * 4; // 4 byte aligned the hdr size
  6196. TotalLength = HLength + NameLength + SendLength;
  6197. CTECountedAllocMem ((PVOID *)&pDgramHdr,TotalLength);
  6198. if (!pDgramHdr)
  6199. {
  6200. return(STATUS_INSUFFICIENT_RESOURCES);
  6201. }
  6202. *ppDgramHdr = pDgramHdr;
  6203. // fill in the Dgram header
  6204. pDgramHdr->Flags = FIRST_DGRAM | (NbtConfig.PduNodeType >> 11);
  6205. TransactId = GetTransactId();
  6206. pDgramHdr->DgramId = htons(TransactId);
  6207. #ifdef _NETBIOSLESS
  6208. pDgramHdr->SrcPort = htons(pDeviceContext->DatagramPort);
  6209. if (IsDeviceNetbiosless(pDeviceContext))
  6210. {
  6211. // We don't know which adapter will be used, so use ANY
  6212. pDgramHdr->SrcIpAddr = htonl(IP_ANY_ADDRESS);
  6213. }
  6214. else
  6215. {
  6216. pDgramHdr->SrcIpAddr = htonl(pDeviceContext->IpAddress);
  6217. }
  6218. #else
  6219. pDgramHdr->SrcPort = htons(NBT_DATAGRAM_UDP_PORT);
  6220. pDgramHdr->SrcIpAddr = htonl(pDeviceContext->IpAddress);
  6221. #endif
  6222. //
  6223. // the length is the standard datagram length (dgram_hdr_size + 2* scope)
  6224. // minus size of the header that comes before the SourceName
  6225. //
  6226. pDgramHdr->DgramLength = htons( (USHORT)SendLength + (USHORT)DGRAM_HDR_SIZE
  6227. - (USHORT)(&((tDGRAMHDR *)0)->SrcName.NameLength)
  6228. + ( (USHORT)(NbtConfig.ScopeLength << 1) ));
  6229. pDgramHdr->PckOffset = 0; // not fragmented for now!
  6230. pCopyTo = (PVOID)&pDgramHdr->SrcName.NameLength;
  6231. pCopyTo = ConvertToHalfAscii(pCopyTo, pSourceName, NbtConfig.pScope, NbtConfig.ScopeLength);
  6232. //
  6233. // copy the destination name and scope to the pdu - we use this node's
  6234. //
  6235. ConvertToHalfAscii (pCopyTo, pDestName, NbtConfig.pScope, NbtConfig.ScopeLength);
  6236. //
  6237. // copy the name in to the buffer since we are completing the client's irp
  6238. // and we will lose his buffer with the dest name in it.
  6239. //
  6240. pNameBuffer = (PVOID)((PUCHAR)pDgramHdr + HLength);
  6241. CTEMemCopy (pNameBuffer, pDestName, NameLength);
  6242. //
  6243. // copy the client's send buffer to our buffer so the send dgram can
  6244. // complete immediately.
  6245. //
  6246. pSendBuffer = (PVOID) ((PUCHAR)pDgramHdr + NameLength + HLength);
  6247. if (SendLength)
  6248. {
  6249. #ifdef VXD
  6250. CTEMemCopy(pSendBuffer,pBuffer,SendLength);
  6251. #else
  6252. status = TdiCopyMdlToBuffer(pBuffer,
  6253. 0,
  6254. pSendBuffer,
  6255. 0,
  6256. SendLength,
  6257. &BytesCopied);
  6258. if (!NT_SUCCESS(status) || (BytesCopied != SendLength))
  6259. {
  6260. CTECountedFreeMem ((PVOID)pDgramHdr, TotalLength, FALSE);
  6261. return(STATUS_UNSUCCESSFUL);
  6262. }
  6263. #endif
  6264. }
  6265. else
  6266. {
  6267. pSendBuffer = NULL;
  6268. }
  6269. //
  6270. // get a buffer for tracking Dgram Sends
  6271. //
  6272. status = GetTracker(&pTracker, NBT_TRACKER_BUILD_SEND_DGRAM);
  6273. if (NT_SUCCESS(status))
  6274. {
  6275. CHECK_PTR(pTracker);
  6276. pTracker->SendBuffer.pBuffer = pSendBuffer;
  6277. pTracker->SendBuffer.Length = SendLength;
  6278. pTracker->SendBuffer.pDgramHdr = pDgramHdr;
  6279. pTracker->SendBuffer.HdrLength = HdrLength;
  6280. pTracker->pClientIrp = NULL;
  6281. pTracker->pDestName = pNameBuffer;
  6282. pTracker->UnicodeDestName = NULL;
  6283. pTracker->pNameAddr = NULL;
  6284. pTracker->RemoteNameLength = NameLength; // May be needed for Dns Name resolution
  6285. pTracker->pClientEle = NULL;
  6286. pTracker->AllocatedLength = TotalLength;
  6287. *ppTracker = pTracker;
  6288. status = STATUS_SUCCESS;
  6289. }
  6290. else
  6291. {
  6292. CTECountedFreeMem((PVOID)pDgramHdr,TotalLength, FALSE);
  6293. status = STATUS_INSUFFICIENT_RESOURCES;
  6294. }
  6295. return(status);
  6296. }
  6297. //----------------------------------------------------------------------------
  6298. VOID
  6299. DgramSendCleanupTracker(
  6300. IN tDGRAM_SEND_TRACKING *pTracker,
  6301. IN NTSTATUS status,
  6302. IN BOOLEAN fJointLockHeld
  6303. )
  6304. /*++
  6305. Routine Description
  6306. This routine cleans up after a data gram send.
  6307. Arguments:
  6308. pTracker
  6309. status
  6310. Length
  6311. Return Values:
  6312. VOID
  6313. --*/
  6314. {
  6315. tNAMEADDR *pNameAddr=NULL;
  6316. //
  6317. // Undo the nameAddr increment done before the send started - if we have
  6318. // actually resolved the name - when the name does not resolve pNameAddr
  6319. // is set to NULL before calling this routine.
  6320. //
  6321. if (pTracker->pNameAddr)
  6322. {
  6323. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_SEND_DGRAM, fJointLockHeld);
  6324. }
  6325. if (pTracker->p1CNameAddr)
  6326. {
  6327. NBT_DEREFERENCE_NAMEADDR (pTracker->p1CNameAddr, REF_NAME_SEND_DGRAM, fJointLockHeld);
  6328. pTracker->p1CNameAddr = NULL;
  6329. }
  6330. //
  6331. // free the buffer used for sending the data and free
  6332. // the tracker
  6333. //
  6334. CTECountedFreeMem((PVOID)pTracker->SendBuffer.pDgramHdr, pTracker->AllocatedLength, fJointLockHeld);
  6335. if (pTracker->pGroupList)
  6336. {
  6337. CTEMemFree(pTracker->pGroupList);
  6338. pTracker->pGroupList = NULL;
  6339. }
  6340. FreeTracker (pTracker,RELINK_TRACKER);
  6341. }
  6342. //----------------------------------------------------------------------------
  6343. NTSTATUS
  6344. NbtSendDatagram(
  6345. IN TDI_REQUEST *pRequest,
  6346. IN PTDI_CONNECTION_INFORMATION pSendInfo,
  6347. IN LONG SendLength,
  6348. IN LONG *pSentLength,
  6349. IN PVOID pBuffer,
  6350. IN tDEVICECONTEXT *pDeviceContext,
  6351. IN PIRP pIrp
  6352. )
  6353. /*++
  6354. Routine Description
  6355. This routine handles sending client data to the Transport TDI
  6356. interface. It is mostly a pass through routine for the data
  6357. except that this code must create a datagram header and pass that
  6358. header back to the calling routine.
  6359. Arguments:
  6360. Return Values:
  6361. NTSTATUS - status of the request
  6362. --*/
  6363. {
  6364. TDI_ADDRESS_NETBT_INTERNAL TdiAddr;
  6365. tCLIENTELE *pClientEle;
  6366. tDGRAMHDR *pDgramHdr;
  6367. NTSTATUS status;
  6368. tDGRAM_SEND_TRACKING *pTracker;
  6369. PCHAR pName, pEndpointName;
  6370. ULONG NameLen;
  6371. ULONG NameType;
  6372. ULONG SendCount;
  6373. tIPADDRESS RemoteIpAddress;
  6374. tDEVICECONTEXT *pDeviceContextOut = NULL;
  6375. PIO_STACK_LOCATION pIrpSp;
  6376. PUCHAR pCopyTo;
  6377. NBT_WORK_ITEM_CONTEXT *pContext;
  6378. CTEPagedCode();
  6379. //
  6380. // Check for valid address on this Device + valid ClientElement
  6381. if ((pDeviceContext->IpAddress == 0) ||
  6382. (pDeviceContext->pFileObjects == NULL))
  6383. {
  6384. return(STATUS_INVALID_DEVICE_REQUEST);
  6385. }
  6386. pClientEle = (tCLIENTELE *)pRequest->Handle.AddressHandle;
  6387. if ( pClientEle->Verify != NBT_VERIFY_CLIENT )
  6388. {
  6389. if ( pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN )
  6390. {
  6391. status = STATUS_CANCELLED;
  6392. }
  6393. else
  6394. {
  6395. status = STATUS_INVALID_HANDLE;
  6396. }
  6397. return status;
  6398. }
  6399. //
  6400. // Check for valid destination name and for whether it is an IP address
  6401. //
  6402. status = GetNetBiosNameFromTransportAddress (
  6403. (PTRANSPORT_ADDRESS)pSendInfo->RemoteAddress, pSendInfo->RemoteAddressLength, &TdiAddr);
  6404. if (!NT_SUCCESS(status))
  6405. {
  6406. IF_DBG(NBT_DEBUG_SEND)
  6407. KdPrint(("Nbt.NbtSendDatagram: Unable to get dest name from address in dgramsend\n"));
  6408. return(STATUS_INVALID_PARAMETER);
  6409. }
  6410. pName = TdiAddr.OEMRemoteName.Buffer;
  6411. NameLen = TdiAddr.OEMRemoteName.Length;
  6412. NameType = TdiAddr.NameType;
  6413. if (TdiAddr.OEMEndpointName.Buffer) {
  6414. CTEMemCopy (pClientEle->EndpointName, TdiAddr.OEMEndpointName.Buffer, NETBIOS_NAME_SIZE);
  6415. }
  6416. pClientEle->AddressType = TdiAddr.AddressType;
  6417. if (RemoteIpAddress = Nbt_inet_addr(pName, DGRAM_SEND_FLAG))
  6418. {
  6419. pDeviceContextOut = GetDeviceFromInterface (htonl(RemoteIpAddress), TRUE);
  6420. if ((NbtConfig.ConnectOnRequestedInterfaceOnly) &&
  6421. (!IsDeviceNetbiosless(pDeviceContext)) &&
  6422. (pDeviceContext != pDeviceContextOut))
  6423. {
  6424. status = STATUS_BAD_NETWORK_PATH;
  6425. goto NbtSendDatagram_Exit;
  6426. }
  6427. }
  6428. #ifndef VXD
  6429. if (pClientEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX)
  6430. {
  6431. pEndpointName = pClientEle->EndpointName;
  6432. }
  6433. else
  6434. #endif // !VXD
  6435. {
  6436. pEndpointName = pName;
  6437. }
  6438. IF_DBG(NBT_DEBUG_SEND)
  6439. KdPrint(("Nbt.NbtSendDatagram: Dgram Send to = %16.16s<%X>\n",pName,pName[15]));
  6440. status = BuildSendDgramHdr (SendLength,
  6441. pDeviceContext,
  6442. ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name, // Source name
  6443. pEndpointName,
  6444. NameLen,
  6445. pBuffer,
  6446. &pDgramHdr,
  6447. &pTracker);
  6448. if (!NT_SUCCESS(status))
  6449. {
  6450. goto NbtSendDatagram_Exit;
  6451. }
  6452. //
  6453. // save the devicecontext that the client is sending on.
  6454. //
  6455. pTracker->pDeviceContext = (PVOID)pDeviceContext;
  6456. pTracker->Flags = DGRAM_SEND_FLAG;
  6457. pTracker->pClientIrp = pIrp;
  6458. pTracker->AddressType = pClientEle->AddressType;
  6459. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  6460. pIrpSp->Parameters.Others.Argument4 = pTracker;
  6461. status = NTCheckSetCancelRoutine(pIrp, NbtCancelDgramSend, pDeviceContext);
  6462. if (STATUS_CANCELLED == status)
  6463. {
  6464. IF_DBG(NBT_DEBUG_SEND)
  6465. KdPrint(("Nbt.NbtSendDatagram: Request was cancelled!\n"));
  6466. pTracker->pClientIrp = NULL;
  6467. pIrpSp->Parameters.Others.Argument4 = NULL;
  6468. DgramSendCleanupTracker(pTracker,status,FALSE);
  6469. goto NbtSendDatagram_Exit;
  6470. }
  6471. if (RemoteIpAddress)
  6472. {
  6473. //
  6474. // add this address to the remote hashtable
  6475. //
  6476. status = LockAndAddToHashTable (NbtConfig.pRemoteHashTbl,
  6477. pName,
  6478. NbtConfig.pScope,
  6479. RemoteIpAddress,
  6480. NBT_UNIQUE,
  6481. NULL,
  6482. NULL,
  6483. pDeviceContextOut,
  6484. NAME_RESOLVED_BY_IP);
  6485. if (NT_SUCCESS (status)) // SUCCESS if added first time, PENDING if name already existed!
  6486. {
  6487. status = STATUS_SUCCESS;
  6488. }
  6489. }
  6490. else
  6491. {
  6492. //
  6493. // if the name is longer than 16 bytes, it's not a netbios name.
  6494. // skip wins, broadcast etc. and go straight to dns resolution
  6495. //
  6496. status = STATUS_UNSUCCESSFUL;
  6497. if (NameLen <= NETBIOS_NAME_SIZE)
  6498. {
  6499. status = FindNameOrQuery(pName,
  6500. pDeviceContext,
  6501. SendDgramContinue,
  6502. pTracker,
  6503. (ULONG) (NAMETYPE_UNIQUE | NAMETYPE_GROUP | NAMETYPE_INET_GROUP),
  6504. &pTracker->RemoteIpAddress,
  6505. &pTracker->pNameAddr,
  6506. REF_NAME_SEND_DGRAM,
  6507. TRUE);
  6508. }
  6509. if ((NameLen > NETBIOS_NAME_SIZE) ||
  6510. ((IsDeviceNetbiosless(pDeviceContext)) && (!NT_SUCCESS(status))))
  6511. {
  6512. if (pContext = (NBT_WORK_ITEM_CONTEXT*)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('H')))
  6513. {
  6514. pContext->pTracker = NULL; // no query tracker
  6515. pContext->pClientContext = pTracker; // the client tracker
  6516. pContext->ClientCompletion = SendDgramContinue;
  6517. pContext->pDeviceContext = pDeviceContext;
  6518. //
  6519. // Start the timer so that the request does not hang waiting for Dns!
  6520. //
  6521. StartLmHostTimer(pContext, FALSE);
  6522. status = NbtProcessLmhSvcRequest (pContext, NBT_RESOLVE_WITH_DNS);
  6523. if (!NT_SUCCESS (status))
  6524. {
  6525. CTEMemFree(pContext);
  6526. }
  6527. }
  6528. else
  6529. {
  6530. status = STATUS_INSUFFICIENT_RESOURCES;
  6531. }
  6532. }
  6533. }
  6534. if (status == STATUS_SUCCESS) // If the name was an IP address or was present in the cache
  6535. {
  6536. SendDgramContinue (pTracker, STATUS_SUCCESS);
  6537. status = STATUS_PENDING; // SendDgramContinue will cleanup and complete the Irp
  6538. }
  6539. else if (status != STATUS_PENDING)
  6540. {
  6541. *pSentLength = 0;
  6542. NTClearFindNameInfo (pTracker, &pIrp, pIrp, pIrpSp);
  6543. if (!pIrp)
  6544. {
  6545. status = STATUS_PENDING; // irp is already completed: return pending so we don't complete again
  6546. }
  6547. pTracker->pNameAddr = NULL;
  6548. DgramSendCleanupTracker(pTracker,status,FALSE);
  6549. }
  6550. NbtSendDatagram_Exit:
  6551. if (pDeviceContextOut)
  6552. {
  6553. NBT_DEREFERENCE_DEVICE (pDeviceContextOut, REF_DEV_OUT_FROM_IP, FALSE);
  6554. }
  6555. //
  6556. // return the status to the client.
  6557. //
  6558. return(status);
  6559. }
  6560. //----------------------------------------------------------------------------
  6561. VOID
  6562. SendDgramContinue(
  6563. IN PVOID pContext,
  6564. IN NTSTATUS status
  6565. )
  6566. /*++
  6567. Routine Description
  6568. This routine handles sending client data to the Transport TDI
  6569. interface after the destination name has resolved to an IP address.
  6570. This routine is given as the completion routine to the "QueryNameOnNet" call
  6571. in NbtSendDatagram, above. When a name query response comes in or the
  6572. timer times out after N retries.
  6573. Arguments:
  6574. pContext - ptr to the DGRAM_TRACKER block
  6575. NTSTATUS - completion status
  6576. Return Values:
  6577. VOID
  6578. --*/
  6579. {
  6580. CTELockHandle OldIrq;
  6581. ULONG lNameType;
  6582. tNAMEADDR *pNameAddr = NULL;
  6583. tNAMEADDR *p1CNameAddr = NULL;
  6584. tDGRAM_SEND_TRACKING *pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  6585. tDEVICECONTEXT *pDeviceContext = pTracker->pDeviceContext;
  6586. PIRP pIrp;
  6587. PIO_STACK_LOCATION pIrpSp;
  6588. CHECK_PTR(pTracker);
  6589. DELETE_CLIENT_SECURITY(pTracker);
  6590. //
  6591. // The Tracker can get cleaned up somewhere and reassigned if we fail below
  6592. // causing the pClientIrp ptr to get lost. We need to save the Irp here
  6593. //
  6594. IoAcquireCancelSpinLock(&OldIrq);
  6595. if (pIrp = pTracker->pClientIrp)
  6596. {
  6597. pTracker->pClientIrp = NULL;
  6598. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  6599. ASSERT (pIrpSp->Parameters.Others.Argument4 == pTracker);
  6600. pIrpSp->Parameters.Others.Argument4 = NULL;
  6601. IoSetCancelRoutine(pIrp, NULL);
  6602. }
  6603. IoReleaseCancelSpinLock(OldIrq);
  6604. //
  6605. // We have to reference the Device here for the calls to FindNameRemoteThenLocal,
  6606. // and also for SendDgram
  6607. //
  6608. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6609. if ((pIrp) &&
  6610. (NBT_REFERENCE_DEVICE(pDeviceContext, REF_DEV_DGRAM, TRUE)))
  6611. {
  6612. //
  6613. // attempt to find the destination name in the remote hash table. If its
  6614. // there, then send to it. For 1c names, this node may be the only node
  6615. // with the 1c name registered, so check the local table, since we skipped
  6616. // it if the name ended in 1c.
  6617. //
  6618. if ((status == STATUS_SUCCESS) ||
  6619. (pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c))
  6620. {
  6621. if (pTracker->pNameAddr)
  6622. {
  6623. pNameAddr = pTracker->pNameAddr;
  6624. }
  6625. else
  6626. {
  6627. //
  6628. // Find and reference the Names if they were resolved
  6629. //
  6630. //
  6631. // check if it is a 1C name and if there is a name in the domain list
  6632. // If pNameAddr is not null, then the send to the domainlist will
  6633. // send to the p1CNameAddr after sending to pNameAddr
  6634. //
  6635. if ((pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c) &&
  6636. (p1CNameAddr = FindInDomainList(pTracker->pDestName,&DomainNames.DomainList)))
  6637. {
  6638. NBT_REFERENCE_NAMEADDR (p1CNameAddr, REF_NAME_SEND_DGRAM);
  6639. }
  6640. if (pNameAddr = FindNameRemoteThenLocal(pTracker,&pTracker->RemoteIpAddress,&lNameType))
  6641. {
  6642. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_SEND_DGRAM);
  6643. }
  6644. else
  6645. {
  6646. //
  6647. // if there is no pNameAddr then just make the domain list
  6648. // name the only pNameAddr to send to.
  6649. //
  6650. pNameAddr = p1CNameAddr;
  6651. p1CNameAddr = NULL;
  6652. }
  6653. pTracker->pNameAddr = pNameAddr;
  6654. pTracker->p1CNameAddr = p1CNameAddr;
  6655. }
  6656. }
  6657. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6658. // check if the name resolved or we have a list of domain names
  6659. // derived from the lmhosts file and it is a 1C name send.
  6660. //
  6661. if (pNameAddr)
  6662. {
  6663. // send the first datagram queued to this name
  6664. status = SendDgram(pNameAddr,pTracker);
  6665. }
  6666. else
  6667. {
  6668. status = STATUS_BAD_NETWORK_PATH;
  6669. }
  6670. NBT_DEREFERENCE_DEVICE(pDeviceContext, REF_DEV_DGRAM, FALSE);
  6671. }
  6672. else
  6673. {
  6674. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6675. status = STATUS_INVALID_DEVICE_STATE;
  6676. }
  6677. //
  6678. // set this so that the cleanup routine does not try to dereference
  6679. // the nameAddr
  6680. if (status == STATUS_TIMEOUT)
  6681. {
  6682. status = STATUS_BAD_NETWORK_PATH;
  6683. }
  6684. if (pIrp)
  6685. {
  6686. if (NT_SUCCESS(status))
  6687. {
  6688. NTIoComplete (pIrp, STATUS_SUCCESS,((PTDI_REQUEST_KERNEL_SENDDG)&pIrpSp->Parameters)->SendLength);
  6689. }
  6690. else
  6691. {
  6692. // this is the ERROR handling if something goes wrong with the send
  6693. CTEIoComplete(pIrp,status,0L);
  6694. }
  6695. }
  6696. // a failure ret code means the send failed, so cleanup the tracker etc.
  6697. if (!NT_SUCCESS(status))
  6698. {
  6699. DgramSendCleanupTracker(pTracker,status,FALSE);
  6700. }
  6701. }
  6702. //----------------------------------------------------------------------------
  6703. NTSTATUS
  6704. SendDgram(
  6705. IN tNAMEADDR *pNameAddr,
  6706. IN tDGRAM_SEND_TRACKING *pTracker
  6707. )
  6708. /*++
  6709. Routine Description
  6710. This routine handles sending client data to the Transport TDI
  6711. interface after the destination name has resolved to an IP address. The
  6712. routine specifically handles sending to internet group names where the destination
  6713. is a list of ip addresses.
  6714. The Device must be referenced before calling this routine!
  6715. Arguments:
  6716. pContext - ptr to the DGRAM_TRACKER block
  6717. NTSTATUS - completion status
  6718. Return Values:
  6719. VOID
  6720. --*/
  6721. {
  6722. ULONG IpAddress;
  6723. NTSTATUS status;
  6724. PFILE_OBJECT pFileObject;
  6725. CHECK_PTR(pTracker);
  6726. if (pNameAddr->NameTypeState & NAMETYPE_UNIQUE )
  6727. {
  6728. ((tDGRAMHDR *)pTracker->SendBuffer.pDgramHdr)->MsgType = DIRECT_UNIQUE;
  6729. }
  6730. else if (pNameAddr->Name[0] == '*')
  6731. {
  6732. ((tDGRAMHDR *)pTracker->SendBuffer.pDgramHdr)->MsgType = BROADCAST_DGRAM;
  6733. }
  6734. else
  6735. {
  6736. // must be group, -
  6737. ((tDGRAMHDR *)pTracker->SendBuffer.pDgramHdr)->MsgType = DIRECT_GROUP;
  6738. }
  6739. //
  6740. // if it is an internet group name, then send to the list of addresses
  6741. //
  6742. if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
  6743. {
  6744. status = DatagramDistribution(pTracker,pNameAddr);
  6745. return(STATUS_PENDING); // DatagramDistribution will cleanup if it failed!
  6746. }
  6747. if (pNameAddr->NameTypeState & NAMETYPE_GROUP)
  6748. {
  6749. IpAddress = 0;
  6750. }
  6751. else if (pNameAddr->Verify == REMOTE_NAME)
  6752. {
  6753. IpAddress = pTracker->RemoteIpAddress;
  6754. }
  6755. // LOCAL_NAME Unique
  6756. else if (IsDeviceNetbiosless(pTracker->pDeviceContext)) // use any non-zero value for local address
  6757. {
  6758. IpAddress = LOOP_BACK;
  6759. }
  6760. else
  6761. {
  6762. IpAddress = pTracker->pDeviceContext->IpAddress;
  6763. }
  6764. pTracker->p1CNameAddr = NULL;
  6765. pTracker->IpListIndex = 0; // flag that there are no more addresses in the list
  6766. /*
  6767. * Strict source routing,
  6768. * 1. The machine should be multi-homed.
  6769. * 2. It is not turned off by the registry key.
  6770. * 3. It is a regular device (not cluster device or SMB device).
  6771. */
  6772. if (!IsLocalAddress(IpAddress) && NbtConfig.MultiHomed && NbtConfig.SendDgramOnRequestedInterfaceOnly &&
  6773. pTracker->pDeviceContext->IPInterfaceContext != (ULONG)(-1) &&
  6774. (!IsDeviceNetbiosless(pTracker->pDeviceContext))) {
  6775. ULONG Interface, Metric;
  6776. pTracker->pDeviceContext->pFastQuery(htonl(IpAddress), &Interface, &Metric);
  6777. if (Interface != pTracker->pDeviceContext->IPInterfaceContext) {
  6778. SendDgramCompletion(pTracker, STATUS_SUCCESS, 0);
  6779. return STATUS_PENDING;
  6780. }
  6781. }
  6782. // send the Datagram...
  6783. status = UdpSendDatagram( pTracker,
  6784. IpAddress,
  6785. SendDgramCompletion,
  6786. pTracker, // context for completion
  6787. pTracker->pDeviceContext->DatagramPort,
  6788. NBT_DATAGRAM_SERVICE);
  6789. // the irp will be completed via SendDgramCompletion
  6790. // so don't complete it by the caller too
  6791. return(STATUS_PENDING);
  6792. }
  6793. //----------------------------------------------------------------------------
  6794. extern
  6795. VOID
  6796. SendDgramCompletion(
  6797. IN PVOID pContext,
  6798. IN NTSTATUS status,
  6799. IN ULONG lInfo
  6800. )
  6801. {
  6802. CTELockHandle OldIrq;
  6803. tDGRAM_SEND_TRACKING *pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  6804. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6805. if (pTracker->IpListIndex)
  6806. {
  6807. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6808. SendNextDgramToGroup(pTracker, status); // Further processing will be done here for Group sends
  6809. }
  6810. else
  6811. {
  6812. //
  6813. // Datagram send to a unique name!
  6814. //
  6815. DgramSendCleanupTracker(pTracker,status,TRUE);
  6816. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6817. }
  6818. }
  6819. //----------------------------------------------------------------------------
  6820. VOID
  6821. DelayedSendDgramDist (
  6822. IN tDGRAM_SEND_TRACKING *pTracker,
  6823. IN PVOID pClientContext,
  6824. IN PVOID Unused1,
  6825. IN tDEVICECONTEXT *Unused2
  6826. )
  6827. /*++
  6828. Routine Description:
  6829. This function is called by the Executive Worker thread to send another
  6830. datagram for the 1C name datagram distribution function.
  6831. Arguments:
  6832. Context -
  6833. Return Value:
  6834. none
  6835. --*/
  6836. {
  6837. NTSTATUS status;
  6838. tDEVICECONTEXT *pDeviceContext = pTracker->pDeviceContext;
  6839. IF_DBG(NBT_DEBUG_SEND)
  6840. KdPrint(("Nbt.DelayedSendDgramDist: To name %15.15s<%X>:Ip %X, \n",
  6841. pTracker->pNameAddr->Name,pTracker->pNameAddr->Name[15],pClientContext));
  6842. // send the Datagram...
  6843. if (NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DGRAM, FALSE))
  6844. {
  6845. status = UdpSendDatagram (pTracker,
  6846. (tIPADDRESS) PtrToUlong(pClientContext),
  6847. SendDgramCompletion,
  6848. pTracker,
  6849. #ifdef _NETBIOSLESS
  6850. pTracker->pDeviceContext->DatagramPort,
  6851. #else
  6852. NBT_DATAGRAM_UDP_PORT,
  6853. #endif
  6854. NBT_DATAGRAM_SERVICE);
  6855. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DGRAM, FALSE);
  6856. }
  6857. else
  6858. {
  6859. SendNextDgramToGroup (pTracker, STATUS_BAD_NETWORK_PATH);
  6860. }
  6861. }
  6862. //----------------------------------------------------------------------------
  6863. extern
  6864. VOID
  6865. SendNextDgramToGroup(
  6866. IN tDGRAM_SEND_TRACKING *pTracker,
  6867. IN NTSTATUS status
  6868. )
  6869. /*++
  6870. Routine Description
  6871. This routine is hit when the
  6872. datagram has been sent by the transport and it completes the request back
  6873. to us ( may not have actually sent on the wire though ).
  6874. This routine also handles sending multiple datagrams for the InternetGroup name
  6875. case.
  6876. Arguments:
  6877. pContext - ptr to the DGRAM_TRACKER block
  6878. NTSTATUS - completion status
  6879. Return Values:
  6880. VOID
  6881. --*/
  6882. {
  6883. tIPADDRESS IpAddress;
  6884. CTELockHandle OldIrq;
  6885. // if this an Internet group send, then there may be more addresses in
  6886. // the list to send to. So check the IpListIndex. For single
  6887. // sends, this value is set to 0 and the code will jump to the bottom
  6888. // where the client's irp will be completed.
  6889. //
  6890. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6891. ASSERT (pTracker->RCount); // RCount is still referenced from the last send
  6892. // The SendCompletion can happen after the Device has been unbound,
  6893. // so check for that also!
  6894. if ((NT_SUCCESS(status)) &&
  6895. (pTracker->IpListIndex < END_DGRAM_DISTRIBUTION))
  6896. {
  6897. IpAddress = pTracker->pGroupList[pTracker->IpListIndex++];
  6898. if (IpAddress != (tIPADDRESS) -1) // The list ends in a -1 ipaddress, so stop when we see that
  6899. {
  6900. //
  6901. // We already have an RCount reference, so no need to do another one here!
  6902. if (NT_SUCCESS (NTQueueToWorkerThread(NULL,
  6903. DelayedSendDgramDist,
  6904. pTracker,
  6905. ULongToPtr(IpAddress),
  6906. NULL,
  6907. pTracker->pDeviceContext,
  6908. TRUE)))
  6909. {
  6910. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6911. return;
  6912. }
  6913. }
  6914. }
  6915. pTracker->RCount--; // decrement the ref count done during the last send
  6916. pTracker->IpListIndex = END_DGRAM_DISTRIBUTION;
  6917. //
  6918. // Either we failed, or we are done, so if the Timer is running, let it cleanup!
  6919. //
  6920. if (!(pTracker->pTimer) &&
  6921. (pTracker->RCount == 0))
  6922. {
  6923. DgramSendCleanupTracker(pTracker,status,TRUE);
  6924. }
  6925. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6926. }
  6927. //----------------------------------------------------------------------------
  6928. extern
  6929. VOID
  6930. DgramDistTimeout(
  6931. PVOID pContext,
  6932. PVOID pContext2,
  6933. tTIMERQENTRY *pTimerQEntry
  6934. )
  6935. /*++
  6936. Routine Description:
  6937. This routine handles a short timeout on a datagram distribution. It
  6938. checks if the dgram send is hung up in the transport doing an ARP and
  6939. then it does the next dgram send if the first is still hung up.
  6940. Arguments:
  6941. Return Value:
  6942. none
  6943. --*/
  6944. {
  6945. tDGRAM_SEND_TRACKING *pTracker;
  6946. CTELockHandle OldIrq;
  6947. tNAMEADDR *pNameAddr;
  6948. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  6949. if (!pTimerQEntry)
  6950. {
  6951. pTracker->pTimer = NULL;
  6952. if ((pTracker->IpListIndex == END_DGRAM_DISTRIBUTION) &&
  6953. (pTracker->RCount == 0))
  6954. {
  6955. DgramSendCleanupTracker(pTracker,STATUS_SUCCESS,TRUE);
  6956. }
  6957. return;
  6958. }
  6959. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  6960. //
  6961. // After the last dgram has completed the iplistindex will be set
  6962. // to this and it is time to cleanup
  6963. //
  6964. if (pTracker->IpListIndex == END_DGRAM_DISTRIBUTION)
  6965. {
  6966. if (pTracker->RCount == 0)
  6967. {
  6968. IF_DBG(NBT_DEBUG_SEND)
  6969. KdPrint(("Nbt.DgramDistTimeout: Cleanup After DgramDistribution %15.15s<%X> \n",
  6970. pTracker->pNameAddr->Name,pTracker->pNameAddr->Name[15]));
  6971. pTracker->pTimer = NULL;
  6972. DgramSendCleanupTracker(pTracker,STATUS_SUCCESS,TRUE);
  6973. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6974. return;
  6975. }
  6976. else
  6977. {
  6978. //
  6979. // Wait for the dgram that has not completed yet - which may not
  6980. // be the last dgram , since ARP could hold one up much long
  6981. // than all the rest if the destination is dead. so start the timer
  6982. // again....
  6983. //
  6984. }
  6985. }
  6986. else
  6987. {
  6988. if (pTracker->IpListIndex == pTracker->SavedListIndex)
  6989. {
  6990. //
  6991. // The dgram send is hung up in the transport, so do the
  6992. // next one now
  6993. //
  6994. IF_DBG(NBT_DEBUG_SEND)
  6995. KdPrint(("Nbt.DgramDistTimeout: DgramDistribution hung up on ARP forcing next send\n"));
  6996. pTracker->RCount++; // Reference it here since SendDgramToGroup expects this to be ref'ed
  6997. pTimerQEntry->Flags |= TIMER_RESTART;
  6998. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  6999. SendNextDgramToGroup(pTracker,STATUS_SUCCESS);
  7000. return;
  7001. }
  7002. else
  7003. {
  7004. //
  7005. // Save the current index so we can check it the next time the timer
  7006. // expires
  7007. //
  7008. pTracker->SavedListIndex = pTracker->IpListIndex;
  7009. }
  7010. }
  7011. pTimerQEntry->Flags |= TIMER_RESTART;
  7012. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7013. }
  7014. //----------------------------------------------------------------------------
  7015. NTSTATUS
  7016. DatagramDistribution(
  7017. IN tDGRAM_SEND_TRACKING *pTracker,
  7018. IN tNAMEADDR *pNameAddr
  7019. )
  7020. /*++
  7021. Routine Description
  7022. This routine sends a single datagram for a 1C name. It then sends
  7023. the next one when this one completes. This is done so that if
  7024. multiple sends go to the gateway, one does not cancel the next
  7025. when an Arp is necessary to resolve the gateway.
  7026. Arguments:
  7027. pTracker
  7028. pNameAddr
  7029. Return Values:
  7030. VOID
  7031. --*/
  7032. {
  7033. NTSTATUS status = STATUS_UNSUCCESSFUL;
  7034. NTSTATUS Locstatus;
  7035. tIPADDRESS *pIpList;
  7036. ULONG Index;
  7037. tIPADDRESS IpAddress;
  7038. tDEVICECONTEXT *pDeviceContext;
  7039. CTELockHandle OldIrq;
  7040. PIRP pIrp;
  7041. PIO_STACK_LOCATION pIrpSp;
  7042. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  7043. status = GetListOfAllAddrs (pTracker->pNameAddr, pTracker->p1CNameAddr, &pIpList, &Index);
  7044. if (pTracker->p1CNameAddr)
  7045. {
  7046. NBT_DEREFERENCE_NAMEADDR (pTracker->p1CNameAddr, REF_NAME_SEND_DGRAM, TRUE);
  7047. pTracker->p1CNameAddr = NULL;
  7048. }
  7049. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_SEND_DGRAM, TRUE);
  7050. pTracker->pNameAddr = NULL;
  7051. pTracker->RCount = 1; // Send RefCount == 0 when last send completes
  7052. pDeviceContext = pTracker->pDeviceContext;
  7053. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7054. if (STATUS_SUCCESS == status)
  7055. {
  7056. FilterIpAddrsForDevice (pIpList, pTracker->pDeviceContext, &Index);
  7057. pTracker->pGroupList = pIpList;
  7058. //
  7059. // When the proxy calls this routine the allocated length is set to
  7060. // zero. In that case we do not want to broadcast again since it
  7061. // could setup an infinite loop with another proxy on the same
  7062. // subnet.
  7063. //
  7064. if (pTracker->AllocatedLength == 0)
  7065. {
  7066. Index = 1;
  7067. }
  7068. else
  7069. {
  7070. Index = 0;
  7071. }
  7072. IpAddress = pIpList[Index];
  7073. pTracker->SavedListIndex = (USHORT) (Index); // For the next send in SendNextDgramToGroup
  7074. pTracker->IpListIndex = pTracker->SavedListIndex + 1; // For the next send in SendNextDgramToGroup
  7075. if (IpAddress == (ULONG)-1)
  7076. {
  7077. status = STATUS_INVALID_ADDRESS;
  7078. }
  7079. }
  7080. else
  7081. {
  7082. status = STATUS_INSUFFICIENT_RESOURCES;
  7083. }
  7084. if ((NT_SUCCESS(status)) &&
  7085. (NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DGRAM, FALSE)))
  7086. {
  7087. IF_DBG(NBT_DEBUG_SEND)
  7088. KdPrint(("Nbt.DgramDistribution: To name %15.15s<%X>: %X, pTracker=<%p>\n",
  7089. pNameAddr->Name,pNameAddr->Name[15],IpAddress, pTracker));
  7090. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  7091. Locstatus = StartTimer(DgramDistTimeout,
  7092. DGRAM_SEND_TIMEOUT,
  7093. pTracker,
  7094. NULL,
  7095. pTracker,
  7096. NULL,
  7097. pDeviceContext,
  7098. &pTracker->pTimer,
  7099. 1,
  7100. TRUE);
  7101. if (!NT_SUCCESS(Locstatus))
  7102. {
  7103. CHECK_PTR(pTracker);
  7104. pTracker->pTimer = NULL;
  7105. }
  7106. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7107. // send the Datagram...
  7108. status = UdpSendDatagram (pTracker,
  7109. IpAddress,
  7110. SendDgramCompletion,
  7111. pTracker,
  7112. #ifdef _NETBIOSLESS
  7113. pTracker->pDeviceContext->DatagramPort,
  7114. #else
  7115. NBT_DATAGRAM_UDP_PORT,
  7116. #endif
  7117. NBT_DATAGRAM_SERVICE);
  7118. NBT_DEREFERENCE_DEVICE(pDeviceContext, REF_DEV_DGRAM, FALSE);
  7119. }
  7120. if (!NT_SUCCESS(status))
  7121. {
  7122. //
  7123. // we failed to send probably because of a lack of free memory
  7124. //
  7125. IoAcquireCancelSpinLock(&OldIrq);
  7126. //
  7127. // Make sure is still there!
  7128. //
  7129. if (pIrp = pTracker->pClientIrp)
  7130. {
  7131. pTracker->pClientIrp = NULL;
  7132. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  7133. ASSERT (pIrpSp->Parameters.Others.Argument4 == pTracker);
  7134. pIrpSp->Parameters.Others.Argument4 = NULL;
  7135. IoSetCancelRoutine(pIrp, NULL);
  7136. IoReleaseCancelSpinLock(OldIrq);
  7137. if (NT_SUCCESS(status))
  7138. {
  7139. CTEIoComplete(pIrp, STATUS_SUCCESS, 0xFFFFFFFF);
  7140. }
  7141. else
  7142. {
  7143. CTEIoComplete(pIrp, status, 0L);
  7144. }
  7145. }
  7146. else
  7147. {
  7148. IoReleaseCancelSpinLock(OldIrq);
  7149. }
  7150. pTracker->RCount--;
  7151. DgramSendCleanupTracker(pTracker,STATUS_SUCCESS,FALSE);
  7152. }
  7153. return(status);
  7154. }
  7155. //----------------------------------------------------------------------------
  7156. NTSTATUS
  7157. NbtSetEventHandler(
  7158. tCLIENTELE *pClientEle,
  7159. int EventType,
  7160. PVOID pEventHandler,
  7161. PVOID pEventContext
  7162. )
  7163. /*++
  7164. Routine Description
  7165. This routine sets the event handler specified to the clients event procedure
  7166. and saves the corresponding context value to return when that event is signaled.
  7167. Arguments:
  7168. Return Values:
  7169. TDI_STATUS - status of the request
  7170. --*/
  7171. {
  7172. NTSTATUS status;
  7173. CTELockHandle OldIrq;
  7174. // first verify that the client element is valid
  7175. CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status)
  7176. if (!pClientEle->pAddress)
  7177. {
  7178. return(STATUS_UNSUCCESSFUL);
  7179. }
  7180. CTESpinLock(pClientEle,OldIrq);
  7181. IF_DBG(NBT_DEBUG_NAMESRV)
  7182. KdPrint(("Nbt.NbtSetEventHandler: Handler <%x> set for Event <%x>, on name %16.16s<%X>\n",
  7183. pEventHandler, EventType,
  7184. ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name,
  7185. ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name[15]));
  7186. status = STATUS_SUCCESS; // by default;
  7187. if (pEventHandler)
  7188. {
  7189. switch (EventType)
  7190. {
  7191. case TDI_EVENT_CONNECT:
  7192. pClientEle->evConnect = pEventHandler;
  7193. pClientEle->ConEvContext = pEventContext;
  7194. break;
  7195. case TDI_EVENT_DISCONNECT:
  7196. pClientEle->evDisconnect = pEventHandler;
  7197. pClientEle->DiscEvContext = pEventContext;
  7198. break;
  7199. case TDI_EVENT_ERROR:
  7200. pClientEle->evError = pEventHandler;
  7201. pClientEle->ErrorEvContext = pEventContext;
  7202. break;
  7203. case TDI_EVENT_RECEIVE:
  7204. pClientEle->evReceive = pEventHandler;
  7205. pClientEle->RcvEvContext = pEventContext;
  7206. break;
  7207. case TDI_EVENT_RECEIVE_DATAGRAM:
  7208. pClientEle->evRcvDgram = pEventHandler;
  7209. pClientEle->RcvDgramEvContext = pEventContext;
  7210. break;
  7211. case TDI_EVENT_RECEIVE_EXPEDITED:
  7212. pClientEle->evRcvExpedited = pEventHandler;
  7213. pClientEle->RcvExpedEvContext = pEventContext;
  7214. break;
  7215. case TDI_EVENT_SEND_POSSIBLE:
  7216. pClientEle->evSendPossible = pEventHandler;
  7217. pClientEle->SendPossEvContext = pEventContext;
  7218. break;
  7219. case TDI_EVENT_CHAINED_RECEIVE:
  7220. case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
  7221. case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
  7222. case TDI_EVENT_ERROR_EX:
  7223. status = STATUS_UNSUCCESSFUL;
  7224. break;
  7225. default:
  7226. ASSERTMSG("Invalid Event Type passed to SetEventHandler\n", (PVOID)0L);
  7227. status = STATUS_UNSUCCESSFUL;
  7228. }
  7229. }
  7230. else
  7231. { //
  7232. // the event handlers are set to point to the TDI default event handlers
  7233. // and can only be changed to another one, but not to a null address,
  7234. // so if null is passed in, set to default handler.
  7235. //
  7236. switch (EventType)
  7237. {
  7238. case TDI_EVENT_CONNECT:
  7239. #ifndef VXD
  7240. pClientEle->evConnect = TdiDefaultConnectHandler;
  7241. #else
  7242. pClientEle->evConnect = NULL;
  7243. #endif
  7244. pClientEle->ConEvContext = NULL;
  7245. break;
  7246. case TDI_EVENT_DISCONNECT:
  7247. #ifndef VXD
  7248. pClientEle->evDisconnect = TdiDefaultDisconnectHandler;
  7249. #else
  7250. pClientEle->evDisconnect = NULL;
  7251. #endif
  7252. pClientEle->DiscEvContext = NULL;
  7253. break;
  7254. case TDI_EVENT_ERROR:
  7255. #ifndef VXD
  7256. pClientEle->evError = TdiDefaultErrorHandler;
  7257. #else
  7258. pClientEle->evError = NULL;
  7259. #endif
  7260. pClientEle->ErrorEvContext = NULL;
  7261. break;
  7262. case TDI_EVENT_RECEIVE:
  7263. #ifndef VXD
  7264. pClientEle->evReceive = TdiDefaultReceiveHandler;
  7265. #else
  7266. pClientEle->evReceive = NULL;
  7267. #endif
  7268. pClientEle->RcvEvContext = NULL;
  7269. break;
  7270. case TDI_EVENT_RECEIVE_DATAGRAM:
  7271. #ifndef VXD
  7272. pClientEle->evRcvDgram = TdiDefaultRcvDatagramHandler;
  7273. #else
  7274. pClientEle->evRcvDgram = NULL;
  7275. #endif
  7276. pClientEle->RcvDgramEvContext = NULL;
  7277. break;
  7278. case TDI_EVENT_RECEIVE_EXPEDITED:
  7279. #ifndef VXD
  7280. pClientEle->evRcvExpedited = TdiDefaultRcvExpeditedHandler;
  7281. #else
  7282. pClientEle->evRcvExpedited = NULL;
  7283. #endif
  7284. pClientEle->RcvExpedEvContext = NULL;
  7285. break;
  7286. case TDI_EVENT_SEND_POSSIBLE:
  7287. #ifndef VXD
  7288. pClientEle->evSendPossible = TdiDefaultSendPossibleHandler;
  7289. #else
  7290. pClientEle->evSendPossible = NULL;
  7291. #endif
  7292. pClientEle->SendPossEvContext = NULL;
  7293. break;
  7294. case TDI_EVENT_CHAINED_RECEIVE:
  7295. case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
  7296. case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
  7297. case TDI_EVENT_ERROR_EX:
  7298. status = STATUS_UNSUCCESSFUL;
  7299. break;
  7300. default:
  7301. ASSERTMSG("Invalid Event Type passed to SetEventHandler\n", (PVOID)0L);
  7302. status = STATUS_UNSUCCESSFUL;
  7303. }
  7304. }
  7305. CTESpinFree(pClientEle,OldIrq);
  7306. return(status);
  7307. }
  7308. //----------------------------------------------------------------------------
  7309. NTSTATUS
  7310. NbtSendNodeStatus(
  7311. IN tDEVICECONTEXT *pDeviceContext,
  7312. IN PCHAR pName,
  7313. IN tIPADDRESS *pIpAddrs,
  7314. IN PVOID ClientContext,
  7315. IN PVOID CompletionRoutine
  7316. )
  7317. /*++
  7318. Routine Description
  7319. This routine sends a node status message to another node.
  7320. It's called for two reasons:
  7321. 1) in response to nbtstat -a (or -A). In this case, CompletionRoutine that's
  7322. passed in is CopyNodeStatusResponse, and ClientContext is the Irp to be completed
  7323. 2) in response to "net use \\foobar.microsoft.com" (or net use \\11.1.1.3)
  7324. In this case, CompletionRoutine that's passed in is ExtractServerName,
  7325. and ClientContext is the tracker that correspondes to session setup.
  7326. The ip addr(s) s of the destination can be passed in (pIpAddrsList) when we
  7327. want to send an adapter status to a particular host. (case 2 above and
  7328. nbtstat -A pass in the ip address(es) since they don't know the name)
  7329. Note for netbiosless. In this case, the name server file object will be null, and the
  7330. status request will be looped back in UdpSendDatagram.
  7331. Arguments:
  7332. Return Values:
  7333. TDI_STATUS - status of the request
  7334. --*/
  7335. {
  7336. NTSTATUS status;
  7337. tDGRAM_SEND_TRACKING *pTracker;
  7338. ULONG Length;
  7339. PUCHAR pHdr;
  7340. tNAMEADDR *pNameAddr;
  7341. PCHAR pName0;
  7342. tIPADDRESS IpAddress;
  7343. tIPADDRESS UNALIGNED *pAddress;
  7344. tIPADDRESS pIpAddress[2];
  7345. tIPADDRESS *pIpAddrsList = pIpAddrs;
  7346. tDEVICECONTEXT *pDeviceContextOut = NULL;
  7347. DWORD i = 0;
  7348. pName0 = pName;
  7349. if ((pIpAddrsList) ||
  7350. (IpAddress = Nbt_inet_addr (pName, REMOTE_ADAPTER_STAT_FLAG)))
  7351. {
  7352. if (!pIpAddrs)
  7353. {
  7354. pIpAddress[0] = IpAddress;
  7355. pIpAddress[1] = 0;
  7356. pIpAddrsList = pIpAddress;
  7357. }
  7358. if ((*pIpAddrsList == 0) ||
  7359. (*pIpAddrsList == DEFAULT_BCAST_ADDR) ||
  7360. (*pIpAddrsList == pDeviceContext->BroadcastAddress))
  7361. {
  7362. //
  7363. // Can't do a remote adapter status to a 0 IP address or a BCast address
  7364. return(STATUS_INVALID_ADDRESS);
  7365. }
  7366. // caller is expected to make sure list terminates in 0 and is
  7367. // not bigger than MAX_IPADDRS_PER_HOST elements
  7368. while(pIpAddrsList[i])
  7369. {
  7370. i++;
  7371. }
  7372. ASSERT(i<MAX_IPADDRS_PER_HOST);
  7373. i++; // for the trailing 0
  7374. IpAddress = pIpAddrsList[0];
  7375. pDeviceContextOut = GetDeviceFromInterface (htonl(IpAddress), FALSE);
  7376. if ((NbtConfig.ConnectOnRequestedInterfaceOnly) &&
  7377. (!IsDeviceNetbiosless(pDeviceContext)) &&
  7378. (pDeviceContext != pDeviceContextOut))
  7379. {
  7380. return (STATUS_BAD_NETWORK_PATH);
  7381. }
  7382. pName0 = NBT_BROADCAST_NAME;
  7383. }
  7384. IF_DBG(NBT_DEBUG_SEND)
  7385. KdPrint(("Nbt.NbtSendNodeStatus: <%16.16s:%x>, IP=<%x>, Completion=<%p>, Context=<%p>\n",
  7386. pName0, pName0[15], IpAddress, CompletionRoutine, ClientContext));
  7387. status = GetTracker(&pTracker, NBT_TRACKER_SEND_NODE_STATUS);
  7388. if (!NT_SUCCESS(status))
  7389. {
  7390. return(status);
  7391. }
  7392. // fill in the tracker data block
  7393. // note that the passed in transport address must stay valid till this
  7394. // send completes
  7395. pTracker->SendBuffer.pDgramHdr = NULL;
  7396. pTracker->SendBuffer.pBuffer = NULL;
  7397. pTracker->SendBuffer.Length = 0;
  7398. pTracker->Flags = REMOTE_ADAPTER_STAT_FLAG;
  7399. pTracker->RefCount = 2; // 1 for the send completion + 1 for the node status completion
  7400. pTracker->pDestName = pName0;
  7401. pTracker->UnicodeDestName = NULL;
  7402. pTracker->RemoteNameLength = NETBIOS_NAME_SIZE; // May be needed for Dns Name resolution
  7403. pTracker->pDeviceContext = pDeviceContext;
  7404. pTracker->pNameAddr = NULL;
  7405. pTracker->ClientCompletion = CompletionRoutine; // FindNameO.. may use CompletionRoutine!
  7406. pTracker->ClientContext = ClientContext;
  7407. pTracker->p1CNameAddr = NULL;
  7408. // the node status is almost identical with the query pdu so use it
  7409. // as a basis and adjust it .
  7410. //
  7411. pAddress = (ULONG UNALIGNED *)CreatePdu(pName0,
  7412. NbtConfig.pScope,
  7413. 0L,
  7414. 0,
  7415. eNAME_QUERY,
  7416. (PVOID)&pHdr,
  7417. &Length,
  7418. pTracker);
  7419. if (!pAddress)
  7420. {
  7421. FreeTracker(pTracker,RELINK_TRACKER);
  7422. return(STATUS_INSUFFICIENT_RESOURCES);
  7423. }
  7424. //
  7425. ((PUSHORT)pHdr)[1] &= ~(FL_RECURDESIRE|FL_BROADCAST); // clear the recursion desired and broadcast bit
  7426. pHdr[Length-3] = (UCHAR)QUEST_STATUS; // set the NBSTAT field to 21 rather than 20
  7427. pTracker->SendBuffer.pDgramHdr = (PVOID)pHdr;
  7428. pTracker->SendBuffer.HdrLength = Length;
  7429. if (IpAddress)
  7430. {
  7431. // this 'fake' pNameAddr has to be setup carefully so that the memory
  7432. // is released when NbtDeferenceName is called from SendDgramCompletion
  7433. // Note that this code does not apply to NbtConnect since these names
  7434. // are group names, and NbtConnect will not allow a session to a group
  7435. // name.
  7436. status = STATUS_INSUFFICIENT_RESOURCES;
  7437. if (!(pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('K'))))
  7438. {
  7439. FreeTracker(pTracker,RELINK_TRACKER);
  7440. CTEMemFree(pHdr);
  7441. return(STATUS_INSUFFICIENT_RESOURCES);
  7442. }
  7443. CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
  7444. InitializeListHead (&pNameAddr->Linkage);
  7445. CTEMemCopy (pNameAddr->Name, pName0, NETBIOS_NAME_SIZE ) ;
  7446. pNameAddr->IpAddress = IpAddress;
  7447. pNameAddr->NameTypeState = NAMETYPE_GROUP | STATE_RESOLVED;
  7448. pNameAddr->Verify = LOCAL_NAME;
  7449. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_NODE_STATUS);
  7450. if (pDeviceContextOut)
  7451. {
  7452. pNameAddr->AdapterMask = pDeviceContextOut->AdapterMask;
  7453. }
  7454. pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
  7455. if (!(pNameAddr->pIpAddrsList = NbtAllocMem(i*sizeof(ULONG),NBT_TAG('M'))))
  7456. {
  7457. FreeTracker(pTracker,RELINK_TRACKER);
  7458. CTEMemFree(pHdr);
  7459. CTEMemFree(pNameAddr);
  7460. return(STATUS_INSUFFICIENT_RESOURCES);
  7461. }
  7462. i = 0;
  7463. do
  7464. {
  7465. pNameAddr->pIpAddrsList[i] = pIpAddrsList[i];
  7466. } while(pIpAddrsList[i++]);
  7467. status = STATUS_SUCCESS;
  7468. }
  7469. else
  7470. {
  7471. status = FindNameOrQuery(pName,
  7472. pDeviceContext,
  7473. SendNodeStatusContinue,
  7474. pTracker,
  7475. (ULONG) NAMETYPE_UNIQUE,
  7476. &IpAddress,
  7477. &pNameAddr,
  7478. REF_NAME_NODE_STATUS,
  7479. FALSE);
  7480. }
  7481. if (status == STATUS_SUCCESS)
  7482. {
  7483. pTracker->RemoteIpAddress = IpAddress;
  7484. pTracker->p1CNameAddr = pNameAddr; // Since we have already Ref'ed
  7485. pNameAddr->IpAddress = IpAddress;
  7486. SendNodeStatusContinue (pTracker, STATUS_SUCCESS);
  7487. status = STATUS_PENDING; // SendNodeStatusContinue will cleanup
  7488. }
  7489. else if (!NT_SUCCESS(status)) // i.e not pending
  7490. {
  7491. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  7492. }
  7493. return(status);
  7494. }
  7495. //----------------------------------------------------------------------------
  7496. VOID
  7497. SendNodeStatusContinue(
  7498. IN PVOID pContext,
  7499. IN NTSTATUS status
  7500. )
  7501. /*++
  7502. Routine Description
  7503. This routine handles sending a node status request to a node after the
  7504. name has been resolved on the net.
  7505. Arguments:
  7506. pContext - ptr to the DGRAM_TRACKER block
  7507. NTSTATUS - completion status
  7508. Return Values:
  7509. VOID
  7510. --*/
  7511. {
  7512. tDGRAM_SEND_TRACKING *pTracker;
  7513. CTELockHandle OldIrq, OldIrq1;
  7514. tNAMEADDR *pNameAddr = NULL;
  7515. ULONG lNameType;
  7516. tTIMERQENTRY *pTimerEntry;
  7517. ULONG IpAddress;
  7518. PCTE_IRP pIrp;
  7519. COMPLETIONCLIENT pClientCompletion;
  7520. PVOID pClientContext;
  7521. pTracker = (tDGRAM_SEND_TRACKING *) pContext;
  7522. ASSERT (NBT_VERIFY_HANDLE (pTracker, NBT_VERIFY_TRACKER));
  7523. ASSERT (pTracker->TrackerType == NBT_TRACKER_SEND_NODE_STATUS);
  7524. DELETE_CLIENT_SECURITY(pTracker);
  7525. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  7526. //
  7527. // attempt to find the destination name in the remote hash table. If its
  7528. // there, then send to it.
  7529. //
  7530. lNameType = NAMETYPE_UNIQUE;
  7531. if ((status == STATUS_SUCCESS) &&
  7532. ((pTracker->p1CNameAddr) ||
  7533. (pNameAddr = FindNameRemoteThenLocal(pTracker, &IpAddress, &lNameType))))
  7534. {
  7535. //
  7536. // found the name in the remote hash table, so send to it after
  7537. // starting a timer to be sure we really do get a response
  7538. //
  7539. status = StartTimer(NodeStatusTimeout,
  7540. NbtConfig.uRetryTimeout,
  7541. pTracker, // Timer context value
  7542. NULL, // Timer context2 value
  7543. pTracker->ClientContext, // ClientContext
  7544. pTracker->ClientCompletion, // ClientCompletion
  7545. pTracker->pDeviceContext,
  7546. &pTimerEntry,
  7547. NbtConfig.uNumRetries,
  7548. TRUE);
  7549. if (NT_SUCCESS(status))
  7550. {
  7551. if (pNameAddr)
  7552. {
  7553. // increment refcount so the name does not disappear
  7554. // dereference when we get the response or timeout
  7555. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_NODE_STATUS);
  7556. pTracker->RemoteIpAddress = IpAddress;
  7557. }
  7558. else
  7559. {
  7560. //
  7561. // This name was already Referenced either in NbtSendNodeStatus
  7562. // or FindNameOrQuery
  7563. //
  7564. pNameAddr = pTracker->p1CNameAddr;
  7565. pTracker->p1CNameAddr = NULL;
  7566. IpAddress = pTracker->RemoteIpAddress;
  7567. }
  7568. pTracker->pNameAddr = pNameAddr;
  7569. pTracker->pTimer = pTimerEntry;
  7570. //
  7571. // Save the transaction ID so that we can match it later on
  7572. //
  7573. pTracker->TransactionId = ((tNAMEHDR*)(pTracker->SendBuffer.pDgramHdr))->TransactId;
  7574. // send the Datagram...
  7575. // the tracker block is put on a global Q in the Config
  7576. // data structure to keep track of it.
  7577. //
  7578. ExInterlockedInsertTailList(&NbtConfig.NodeStatusHead,
  7579. &pTracker->Linkage,
  7580. &NbtConfig.LockInfo.SpinLock);
  7581. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7582. status = UdpSendDatagram (pTracker,
  7583. IpAddress,
  7584. NameDgramSendCompleted,
  7585. pTracker, // context
  7586. #ifdef _NETBIOSLESS
  7587. pTracker->pDeviceContext->NameServerPort,
  7588. #else
  7589. NBT_NAMESERVICE_UDP_PORT,
  7590. #endif
  7591. NBT_NAME_SERVICE);
  7592. if (!(NT_SUCCESS(status)))
  7593. {
  7594. //
  7595. // this undoes one of two ref's added in NbtSendNodeStatus
  7596. //
  7597. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  7598. CTEMemFree(pTracker->SendBuffer.pDgramHdr);
  7599. pTracker->SendBuffer.pDgramHdr = NULL;
  7600. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  7601. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7602. }
  7603. // if the send fails, the timer will resend it...so no need
  7604. // to check the return code here.
  7605. return;
  7606. }
  7607. }
  7608. if (pTracker->p1CNameAddr)
  7609. {
  7610. NBT_DEREFERENCE_NAMEADDR (pTracker->p1CNameAddr, REF_NAME_NODE_STATUS, TRUE);
  7611. pTracker->p1CNameAddr = NULL;
  7612. }
  7613. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7614. // this is the ERROR handling if we failed to resolve the name
  7615. // or the timer did not start
  7616. pClientCompletion = pTracker->ClientCompletion;
  7617. pClientContext = pTracker->ClientContext;
  7618. if (pClientCompletion)
  7619. {
  7620. (*pClientCompletion) (pClientContext, STATUS_UNSUCCESSFUL);
  7621. }
  7622. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  7623. }
  7624. //----------------------------------------------------------------------------
  7625. VOID
  7626. NodeStatusTimeout(
  7627. PVOID pContext,
  7628. PVOID pContext2,
  7629. tTIMERQENTRY *pTimerQEntry
  7630. )
  7631. /*++
  7632. Routine Description:
  7633. This routine handles the NodeStatus timeouts on packets sent to nodes
  7634. that do not respond in a timely manner to node status. This routine will
  7635. resend the request.
  7636. Arguments:
  7637. Return Value:
  7638. The function value is the status of the operation.
  7639. --*/
  7640. {
  7641. NTSTATUS status;
  7642. tDGRAM_SEND_TRACKING *pTracker;
  7643. CTELockHandle OldIrq, OldIrq1;
  7644. COMPLETIONCLIENT pClientCompletion;
  7645. PVOID pClientContext;
  7646. PCHAR pName0;
  7647. PUCHAR pHdr;
  7648. ULONG Length;
  7649. ULONG UNALIGNED *pAddress;
  7650. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  7651. ASSERT (NBT_VERIFY_HANDLE (pTracker, NBT_VERIFY_TRACKER));
  7652. ASSERT (pTracker->TrackerType == NBT_TRACKER_SEND_NODE_STATUS);
  7653. if (!pTimerQEntry)
  7654. {
  7655. //
  7656. // Do not dereference here since Node Status Done will do
  7657. // the dereference
  7658. //
  7659. CTESpinLock(&NbtConfig,OldIrq1);
  7660. RemoveEntryList(&pTracker->Linkage);
  7661. InitializeListHead(&pTracker->Linkage);
  7662. CTESpinFree(&NbtConfig,OldIrq1);
  7663. pTracker->pTimer = NULL;
  7664. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_NODE_STATUS, TRUE);
  7665. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  7666. return;
  7667. }
  7668. CHECK_PTR(pTimerQEntry);
  7669. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  7670. if (pTracker->SendBuffer.pDgramHdr)
  7671. {
  7672. //
  7673. // The timer has expired before the original Datagram
  7674. // could be sent, so just restart the timer!
  7675. //
  7676. pTimerQEntry->Flags |= TIMER_RESTART;
  7677. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7678. return;
  7679. }
  7680. if ((--pTimerQEntry->Retries) == 0)
  7681. {
  7682. pClientCompletion = pTimerQEntry->ClientCompletion;
  7683. pClientContext = pTimerQEntry->ClientContext;
  7684. pTimerQEntry->ClientCompletion = NULL;
  7685. pTracker->pTimer = NULL;
  7686. // if the client routine has not yet run, run it now.
  7687. if (pClientCompletion)
  7688. {
  7689. // unlink the tracker from the node status Q if we successfully
  7690. // called the completion routine. Note, remove from the
  7691. // list before calling the completion routine to coordinate
  7692. // with DecodeNodeStatusResponse in inbound.c
  7693. //
  7694. CTESpinLock(&NbtConfig,OldIrq1);
  7695. RemoveEntryList(&pTracker->Linkage);
  7696. InitializeListHead(&pTracker->Linkage);
  7697. CTESpinFree(&NbtConfig,OldIrq1);
  7698. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_NODE_STATUS, TRUE);
  7699. NBT_DEREFERENCE_TRACKER (pTracker, TRUE);
  7700. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7701. (*pClientCompletion) (pClientContext, STATUS_TIMEOUT);
  7702. }
  7703. else
  7704. {
  7705. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7706. }
  7707. return;
  7708. }
  7709. // send the Datagram...increment ref count
  7710. NBT_REFERENCE_TRACKER (pTracker);
  7711. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7712. //
  7713. // the node status is almost identical with the query pdu so use it
  7714. // as a basis and adjust it . We always rebuild the Node status
  7715. // request since the datagram gets freed when the irp is returned
  7716. // from the transport.
  7717. //
  7718. if (pTracker->p1CNameAddr)
  7719. {
  7720. pName0 = pTracker->p1CNameAddr->Name;
  7721. }
  7722. else
  7723. {
  7724. pName0 = pTracker->pNameAddr->Name;
  7725. }
  7726. pAddress = (ULONG UNALIGNED *)CreatePdu(pName0,
  7727. NbtConfig.pScope,
  7728. 0L,
  7729. 0,
  7730. eNAME_QUERY,
  7731. (PVOID)&pHdr,
  7732. &Length,
  7733. pTracker);
  7734. if (pAddress)
  7735. {
  7736. // clear the recursion desired bit
  7737. //
  7738. ((PUSHORT)pHdr)[1] &= ~FL_RECURDESIRE;
  7739. // set the NBSTAT field to 21 rather than 20
  7740. pHdr[Length-3] = (UCHAR)QUEST_STATUS;
  7741. // fill in the tracker data block
  7742. // the passed in transport address must stay valid till this send completes
  7743. pTracker->SendBuffer.pDgramHdr = (PVOID)pHdr;
  7744. status = UdpSendDatagram (pTracker,
  7745. pTracker->pNameAddr->IpAddress,
  7746. NameDgramSendCompleted,
  7747. pTracker,
  7748. #ifdef _NETBIOSLESS
  7749. pTracker->pDeviceContext->NameServerPort,
  7750. #else
  7751. NBT_NAMESERVICE_UDP_PORT,
  7752. #endif
  7753. NBT_NAME_SERVICE);
  7754. }
  7755. else
  7756. {
  7757. status = STATUS_INSUFFICIENT_RESOURCES;
  7758. }
  7759. if (!(NT_SUCCESS(status)))
  7760. {
  7761. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  7762. if (pTracker->SendBuffer.pDgramHdr)
  7763. {
  7764. CTEMemFree(pTracker->SendBuffer.pDgramHdr);
  7765. pTracker->SendBuffer.pDgramHdr = NULL;
  7766. }
  7767. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  7768. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  7769. }
  7770. // always restart even if the above send fails, since it might succeed
  7771. // later.
  7772. pTimerQEntry->Flags |= TIMER_RESTART;
  7773. }
  7774. //----------------------------------------------------------------------------
  7775. #ifndef VXD
  7776. VOID
  7777. NTClearFindNameInfo(
  7778. tDGRAM_SEND_TRACKING *pTracker,
  7779. PIRP *ppClientIrp,
  7780. PIRP pIrp,
  7781. PIO_STACK_LOCATION pIrpSp
  7782. )
  7783. /*++
  7784. Routine Description
  7785. This routine clears the Find Name information from the Tracker
  7786. within the Cancel SpinLock -- since NbtQueryFindNameInfo is a
  7787. pageable function, we have to do this in non-pageable code
  7788. Arguments:
  7789. Return Values:
  7790. none
  7791. --*/
  7792. {
  7793. CTELockHandle OldIrq1;
  7794. IoAcquireCancelSpinLock(&OldIrq1);
  7795. *ppClientIrp = pTracker->pClientIrp;
  7796. if (*ppClientIrp == pIrp)
  7797. {
  7798. pTracker->pClientIrp = NULL;
  7799. }
  7800. pIrpSp->Parameters.Others.Argument4 = NULL;
  7801. IoReleaseCancelSpinLock(OldIrq1);
  7802. }
  7803. #endif // !VXD
  7804. NTSTATUS
  7805. NbtQueryFindName(
  7806. IN PTDI_CONNECTION_INFORMATION pInfo,
  7807. IN tDEVICECONTEXT *pDeviceContext,
  7808. IN PIRP pIrp,
  7809. IN BOOLEAN IsIoctl
  7810. )
  7811. /*++
  7812. Routine Description
  7813. This routine handles a Client's query to find a netbios name. It
  7814. ultimately returns the IP address of the destination.
  7815. Arguments:
  7816. Return Values:
  7817. TDI_STATUS - status of the request
  7818. --*/
  7819. {
  7820. NTSTATUS status;
  7821. tDGRAM_SEND_TRACKING *pTracker;
  7822. PCHAR pName;
  7823. ULONG lNameType;
  7824. tNAMEADDR *pNameAddr;
  7825. PIRP pClientIrp = 0;
  7826. ULONG NameLen;
  7827. TDI_ADDRESS_NETBT_INTERNAL TdiAddr;
  7828. #ifndef VXD
  7829. PIO_STACK_LOCATION pIrpSp;
  7830. #endif
  7831. CTEPagedCode();
  7832. // this routine gets a ptr to the netbios name out of the wierd
  7833. // TDI address syntax.
  7834. if (!IsIoctl)
  7835. {
  7836. ASSERT(pInfo->RemoteAddressLength);
  7837. status = GetNetBiosNameFromTransportAddress((PTRANSPORT_ADDRESS) pInfo->RemoteAddress,
  7838. pInfo->RemoteAddressLength, &TdiAddr);
  7839. pName = TdiAddr.OEMRemoteName.Buffer;
  7840. NameLen = TdiAddr.OEMRemoteName.Length;
  7841. lNameType = TdiAddr.NameType;
  7842. if ((!NT_SUCCESS(status)) ||
  7843. (lNameType != TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ||
  7844. (NameLen > NETBIOS_NAME_SIZE))
  7845. {
  7846. IF_DBG(NBT_DEBUG_SEND)
  7847. KdPrint(("Nbt.NbtQueryFindName: Unable to get dest name from address in QueryFindName\n"));
  7848. return(STATUS_INVALID_PARAMETER);
  7849. }
  7850. }
  7851. #ifndef VXD
  7852. else
  7853. {
  7854. pName = ((tIPADDR_BUFFER *)pInfo)->Name;
  7855. NameLen = NETBIOS_NAME_SIZE;
  7856. }
  7857. #endif
  7858. IF_DBG(NBT_DEBUG_SEND)
  7859. KdPrint(("Nbt.NbtQueryFindName: For = %16.16s<%X>\n",pName,pName[15]));
  7860. //
  7861. // this will query the name on the network and call a routine to
  7862. // finish sending the datagram when the query completes.
  7863. //
  7864. status = GetTracker(&pTracker, NBT_TRACKER_QUERY_FIND_NAME);
  7865. if (!NT_SUCCESS(status))
  7866. {
  7867. return(status);
  7868. }
  7869. pTracker->pClientIrp = pIrp;
  7870. pTracker->pDestName = pName;
  7871. pTracker->UnicodeDestName = NULL;
  7872. pTracker->pDeviceContext = pDeviceContext;
  7873. pTracker->RemoteNameLength = NameLen; // May be needed for Dns Name resolution
  7874. //
  7875. // Set the FIND_NAME_FLAG here to indicate to the DNS name resolution code that
  7876. // this is not a session setup attempt so it can avoid the call to
  7877. // ConvertToHalfAscii (where pSessionHdr is NULL).
  7878. //
  7879. if (IsIoctl)
  7880. {
  7881. // Do not do DNS query for this name since this is from GetHostByName!
  7882. pTracker->Flags = REMOTE_ADAPTER_STAT_FLAG|FIND_NAME_FLAG|NO_DNS_RESOLUTION_FLAG;
  7883. }
  7884. else
  7885. {
  7886. pTracker->Flags = REMOTE_ADAPTER_STAT_FLAG|FIND_NAME_FLAG;
  7887. }
  7888. #ifndef VXD
  7889. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  7890. pIrpSp->Parameters.Others.Argument4 = (PVOID)pTracker;
  7891. status = NTCheckSetCancelRoutine( pIrp, NbtCancelFindName,pDeviceContext );
  7892. if (status == STATUS_CANCELLED )
  7893. {
  7894. FreeTracker(pTracker,RELINK_TRACKER);
  7895. return(status);
  7896. }
  7897. #endif
  7898. status = FindNameOrQuery(pName,
  7899. pDeviceContext,
  7900. QueryNameCompletion,
  7901. pTracker,
  7902. (ULONG) (NAMETYPE_UNIQUE | NAMETYPE_GROUP | NAMETYPE_INET_GROUP),
  7903. &pTracker->RemoteIpAddress,
  7904. &pNameAddr,
  7905. REF_NAME_FIND_NAME,
  7906. FALSE);
  7907. if ((status == STATUS_SUCCESS) || (!NT_SUCCESS(status)))
  7908. {
  7909. #ifndef VXD
  7910. NTClearFindNameInfo (pTracker, &pClientIrp, pIrp, pIrpSp);
  7911. #else
  7912. pClientIrp = pTracker->pClientIrp;
  7913. #endif
  7914. if (pClientIrp)
  7915. {
  7916. ASSERT( pClientIrp == pIrp );
  7917. if (status == STATUS_SUCCESS)
  7918. {
  7919. status = CopyFindNameData(pNameAddr, pIrp, pTracker);
  7920. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_FIND_NAME, FALSE);
  7921. }
  7922. }
  7923. //
  7924. // irp is already completed: return pending so we don't complete again
  7925. //
  7926. else
  7927. {
  7928. if (status == STATUS_SUCCESS)
  7929. {
  7930. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_FIND_NAME, FALSE);
  7931. }
  7932. status = STATUS_PENDING;
  7933. }
  7934. FreeTracker(pTracker, RELINK_TRACKER);
  7935. }
  7936. return(status);
  7937. }
  7938. //----------------------------------------------------------------------------
  7939. VOID
  7940. QueryNameCompletion(
  7941. IN PVOID pContext,
  7942. IN NTSTATUS status
  7943. )
  7944. /*++
  7945. Routine Description
  7946. This routine handles a name query completion that was requested by the
  7947. client. If successful the client is returned the ip address of the name
  7948. passed in the original request.
  7949. Arguments:
  7950. pContext - ptr to the DGRAM_TRACKER block
  7951. NTSTATUS - completion status
  7952. Return Values:
  7953. VOID
  7954. --*/
  7955. {
  7956. tDGRAM_SEND_TRACKING *pTracker;
  7957. CTELockHandle OldIrq1;
  7958. tNAMEADDR *pNameAddr;
  7959. ULONG lNameType;
  7960. PIRP pClientIrp;
  7961. #ifndef VXD
  7962. PIO_STACK_LOCATION pIrpSp;
  7963. //
  7964. // We now use Cancel SpinLocks to check the validity of our Irps
  7965. // This is to prevent a race condition in between the time that
  7966. // the Cancel routine (NbtCancelFindName) releases the Cancel SpinLock
  7967. // and acquires the joint lock and we complete the Irp over here
  7968. //
  7969. IoAcquireCancelSpinLock(&OldIrq1);
  7970. #endif
  7971. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  7972. pClientIrp = pTracker->pClientIrp;
  7973. pTracker->pClientIrp = NULL;
  7974. #ifndef VXD
  7975. //
  7976. // Make sure all parameters are valid for the Irp processing
  7977. //
  7978. if (! ((pClientIrp) &&
  7979. (pIrpSp = IoGetCurrentIrpStackLocation(pClientIrp)) &&
  7980. (pIrpSp->Parameters.Others.Argument4 == pTracker) ) )
  7981. {
  7982. IoReleaseCancelSpinLock(OldIrq1);
  7983. IF_DBG(NBT_DEBUG_NAMESRV)
  7984. KdPrint(("Nbt:QueryNameCompletion: Irp=<%p> was cancelled\n", pClientIrp));
  7985. FreeTracker( pTracker,RELINK_TRACKER );
  7986. return;
  7987. }
  7988. pIrpSp->Parameters.Others.Argument4 = NULL;
  7989. IoSetCancelRoutine(pClientIrp, NULL);
  7990. IoReleaseCancelSpinLock(OldIrq1);
  7991. #endif
  7992. //
  7993. // attempt to find the destination name in the local/remote hash table.
  7994. //
  7995. if ((status == STATUS_SUCCESS) &&
  7996. (NT_SUCCESS(status = CopyFindNameData (NULL, pClientIrp, pTracker))))
  7997. {
  7998. CTEIoComplete(pClientIrp,status,0xFFFFFFFF);
  7999. }
  8000. else
  8001. {
  8002. // this is the ERROR handling if something goes wrong with the send
  8003. CTEIoComplete(pClientIrp,STATUS_IO_TIMEOUT,0L);
  8004. }
  8005. FreeTracker(pTracker,RELINK_TRACKER);
  8006. }
  8007. //----------------------------------------------------------------------------
  8008. NTSTATUS
  8009. CopyFindNameData(
  8010. IN tNAMEADDR *pNameAddr,
  8011. IN PIRP pIrp,
  8012. IN tDGRAM_SEND_TRACKING *pTracker
  8013. )
  8014. /*++
  8015. Routine Description:
  8016. This Routine copies data received from the net node status response to
  8017. the client's irp.
  8018. Arguments:
  8019. pIrp - a ptr to an IRP
  8020. Return Value:
  8021. NTSTATUS - status of the request
  8022. --*/
  8023. {
  8024. NTSTATUS status;
  8025. PFIND_NAME_HEADER pFindNameHdr;
  8026. PFIND_NAME_BUFFER pFindNameBuffer;
  8027. tIPADDRESS *pIpAddr = NULL;
  8028. ULONG BuffSize;
  8029. ULONG DataLength;
  8030. ULONG NumNames;
  8031. ULONG i;
  8032. ULONG lNameType;
  8033. CTELockHandle OldIrq;
  8034. tIPADDRESS SrcAddress, DestIpAddress;
  8035. tIPADDRESS *pIpAddrBuffer;
  8036. tDEVICECONTEXT *pDeviceContext = pTracker->pDeviceContext;
  8037. SrcAddress = htonl(pDeviceContext->IpAddress);
  8038. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  8039. if (!pNameAddr)
  8040. {
  8041. if (pNameAddr = FindNameRemoteThenLocal (pTracker, &DestIpAddress, &lNameType))
  8042. {
  8043. pNameAddr->IpAddress = DestIpAddress;
  8044. }
  8045. else
  8046. {
  8047. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  8048. return (STATUS_IO_TIMEOUT);
  8049. }
  8050. }
  8051. status = GetListOfAllAddrs(pNameAddr, NULL, &pIpAddr, &NumNames);
  8052. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  8053. if (STATUS_SUCCESS != status)
  8054. {
  8055. return (STATUS_IO_TIMEOUT);
  8056. }
  8057. #ifdef VXD
  8058. DataLength = ((NCB*)pIrp)->ncb_length ;
  8059. #else
  8060. DataLength = MmGetMdlByteCount( pIrp->MdlAddress ) ;
  8061. #endif
  8062. BuffSize = sizeof(FIND_NAME_HEADER) + NumNames*sizeof(FIND_NAME_BUFFER);
  8063. //
  8064. // Make sure we don't overflow our buffer
  8065. //
  8066. if (BuffSize > DataLength)
  8067. {
  8068. if (DataLength <= sizeof(FIND_NAME_HEADER))
  8069. {
  8070. NumNames = 0 ;
  8071. }
  8072. else
  8073. {
  8074. NumNames = (DataLength - sizeof(FIND_NAME_HEADER)) / sizeof(FIND_NAME_BUFFER) ;
  8075. }
  8076. BuffSize = sizeof(FIND_NAME_HEADER) + NumNames*sizeof(FIND_NAME_BUFFER);
  8077. }
  8078. // sanity check that we are not allocating more than 64K for this stuff
  8079. if (BuffSize > 0xFFFF)
  8080. {
  8081. return(STATUS_UNSUCCESSFUL);
  8082. }
  8083. else if ((NumNames == 0) ||
  8084. (!(pFindNameHdr = NbtAllocMem ((USHORT)BuffSize, NBT_TAG('N')))))
  8085. {
  8086. if (pIpAddr)
  8087. {
  8088. CTEMemFree((PVOID)pIpAddr);
  8089. }
  8090. return(STATUS_INSUFFICIENT_RESOURCES);
  8091. }
  8092. // Fill out the find name structure with zeros first
  8093. CTEZeroMemory((PVOID)pFindNameHdr,BuffSize);
  8094. pFindNameBuffer = (PFIND_NAME_BUFFER)((PUCHAR)pFindNameHdr + sizeof(FIND_NAME_HEADER));
  8095. pFindNameHdr->node_count = (USHORT)NumNames;
  8096. pFindNameHdr->unique_group = (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ? UNIQUE_NAME : GROUP_NAME;
  8097. for (i=0;i < NumNames ;i++)
  8098. {
  8099. // Note: the source and destination address appear to be
  8100. // reversed since they are supposed to be the source and
  8101. // destination of the response to the findname query, hence
  8102. // the destination of the response is this node and the
  8103. // source is the other node.
  8104. *(tIPADDRESS UNALIGNED *) &pFindNameBuffer->source_addr[2] = htonl(pIpAddr[i]);
  8105. *(tIPADDRESS UNALIGNED *) &pFindNameBuffer->destination_addr[2] = SrcAddress;
  8106. pFindNameBuffer++;
  8107. }
  8108. #ifdef VXD
  8109. CTEMemCopy (((NCB*)pIrp)->ncb_buffer, pFindNameHdr, BuffSize);
  8110. ASSERT( ((NCB*)pIrp)->ncb_length >= BuffSize ) ;
  8111. ((NCB*)pIrp)->ncb_length = BuffSize ;
  8112. status = STATUS_SUCCESS ;
  8113. #else
  8114. //
  8115. // copy the buffer to the client's MDL
  8116. //
  8117. status = TdiCopyBufferToMdl (pFindNameHdr, 0, BuffSize, pIrp->MdlAddress, 0, &DataLength);
  8118. pIrp->IoStatus.Information = DataLength;
  8119. pIrp->IoStatus.Status = status;
  8120. #endif
  8121. if (pIpAddr)
  8122. {
  8123. CTEMemFree((PVOID)pIpAddr);
  8124. }
  8125. CTEMemFree((PVOID)pFindNameHdr);
  8126. return(status);
  8127. }
  8128. //----------------------------------------------------------------------------
  8129. NTSTATUS
  8130. NbtAddEntryToRemoteHashTable(
  8131. IN tDEVICECONTEXT *pDeviceContext,
  8132. IN USHORT NameAddFlag,
  8133. IN PUCHAR Name,
  8134. IN ULONG IpAddress,
  8135. IN ULONG Ttl, // in seconds
  8136. IN UCHAR name_flags
  8137. )
  8138. {
  8139. NTSTATUS status;
  8140. tNAMEADDR *pNameAddr;
  8141. CTELockHandle OldIrq;
  8142. CTESpinLock (&NbtConfig.JointLock, OldIrq);
  8143. //
  8144. // We need only the name, IpAddress, name_flags, and Ttl fields
  8145. //
  8146. if (STATUS_SUCCESS == FindInHashTable (NbtConfig.pRemoteHashTbl,
  8147. Name, NbtConfig.pScope, &pNameAddr))
  8148. {
  8149. status = STATUS_DUPLICATE_NAME;
  8150. }
  8151. else if (pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('8')))
  8152. {
  8153. CTEZeroMemory (pNameAddr,sizeof(tNAMEADDR));
  8154. InitializeListHead (&pNameAddr->Linkage);
  8155. pNameAddr->Verify = REMOTE_NAME;
  8156. if (NameAddFlag & NAME_RESOLVED_BY_CLIENT)
  8157. {
  8158. pNameAddr->AdapterMask = (CTEULONGLONG)-1;
  8159. }
  8160. else if (pDeviceContext)
  8161. {
  8162. pNameAddr->AdapterMask = pDeviceContext->AdapterMask;
  8163. }
  8164. //
  8165. // Now copy the user-supplied data
  8166. //
  8167. CTEMemCopy (pNameAddr->Name,Name,NETBIOS_NAME_SIZE);
  8168. pNameAddr->TimeOutCount = (USHORT) (Ttl / (REMOTE_HASH_TIMEOUT/1000)) + 1;
  8169. pNameAddr->IpAddress = IpAddress;
  8170. if (name_flags & GROUP_STATUS)
  8171. {
  8172. pNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_GROUP;
  8173. }
  8174. else
  8175. {
  8176. pNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_UNIQUE;
  8177. }
  8178. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE);
  8179. status = AddToHashTable(NbtConfig.pRemoteHashTbl,
  8180. pNameAddr->Name,
  8181. NbtConfig.pScope,
  8182. IpAddress,
  8183. 0,
  8184. pNameAddr,
  8185. NULL,
  8186. pDeviceContext,
  8187. NameAddFlag);
  8188. //
  8189. // If AddToHashTable fails, it will free the pNameAddr structure
  8190. // within itself, so no need to cleanup here!
  8191. //
  8192. if (NT_SUCCESS (status)) // SUCCESS if added first time, PENDING if name already existed!
  8193. {
  8194. status = STATUS_SUCCESS;
  8195. }
  8196. if (status == STATUS_SUCCESS && NameAddFlag & NAME_RESOLVED_BY_CLIENT) {
  8197. //
  8198. // this prevents the name from being deleted by the Hash Timeout code
  8199. //
  8200. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_PRELOADED);
  8201. pNameAddr->Ttl = 0xFFFFFFFF;
  8202. pNameAddr->NameTypeState |= PRELOADED | STATE_RESOLVED;
  8203. pNameAddr->NameTypeState &= ~STATE_CONFLICT;
  8204. pNameAddr->AdapterMask = (CTEULONGLONG)-1;
  8205. }
  8206. }
  8207. else
  8208. {
  8209. status = STATUS_INSUFFICIENT_RESOURCES;
  8210. }
  8211. CTESpinFree (&NbtConfig.JointLock, OldIrq);
  8212. IF_DBG(NBT_DEBUG_NAMESRV)
  8213. KdPrint(("Nbt.NbtAddEntryToRemoteHashTable: Name=<%16.16s:%x>, status=<%x>\n",
  8214. Name, Name[15], status));
  8215. return status;
  8216. }
  8217. //----------------------------------------------------------------------------
  8218. NTSTATUS
  8219. NbtQueryAdapterStatus(
  8220. IN tDEVICECONTEXT *pDeviceContext,
  8221. OUT PVOID *ppAdapterStatus,
  8222. IN OUT PLONG pSize,
  8223. enum eNbtLocation Location
  8224. )
  8225. /*++
  8226. Routine Description
  8227. This routine creates a list of netbios names that are registered and
  8228. returns a pointer to the list in pAdapterStatus.
  8229. This routine can be called with a Null DeviceContext meaning, get the
  8230. remote hash table names, rather than the local hash table names.
  8231. Arguments:
  8232. Return Values:
  8233. TDI_STATUS - status of the request
  8234. --*/
  8235. {
  8236. NTSTATUS status;
  8237. CTELockHandle OldIrq1;
  8238. LONG ActualCount, AllocatedCount;
  8239. LONG j;
  8240. LONG BuffSize;
  8241. PADAPTER_STATUS pAdapterStatus;
  8242. PLIST_ENTRY pEntry;
  8243. PLIST_ENTRY pHead;
  8244. PNAME_BUFFER pNameBuffer;
  8245. tADDRESSELE *pAddressEle;
  8246. tNAMEADDR *pNameAddr;
  8247. tHASHTABLE *pHashTable;
  8248. ULONG NameSize;
  8249. USHORT MaxAllowed;
  8250. PUCHAR pMacAddr;
  8251. tIPADDRESS IpAddress;
  8252. tIPADDRESS *pIpNbtGroupList;
  8253. ULONG Ttl;
  8254. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  8255. AllocatedCount = 0;
  8256. if (Location == NBT_LOCAL) // ==> Local Hash table
  8257. {
  8258. pHashTable = NbtConfig.pLocalHashTbl;
  8259. NameSize = sizeof(NAME_BUFFER);
  8260. }
  8261. else // ==> Remote Hash table
  8262. {
  8263. // get the list of addresses for this device - remote hash table
  8264. pHashTable = NbtConfig.pRemoteHashTbl;
  8265. NameSize = sizeof(tREMOTE_CACHE);
  8266. }
  8267. for (j=0;j < pHashTable->lNumBuckets ;j++ )
  8268. {
  8269. pHead = &pHashTable->Bucket[j];
  8270. pEntry = pHead;
  8271. while ((pEntry = pEntry->Flink) != pHead)
  8272. {
  8273. AllocatedCount++;
  8274. }
  8275. }
  8276. // Allocate Memory for the adapter status
  8277. BuffSize = sizeof(ADAPTER_STATUS) + AllocatedCount*NameSize;
  8278. #ifdef VXD
  8279. //
  8280. // The max BuffSize for Win9x is limited by a UShort,
  8281. // so see if we are going to overflow that
  8282. //
  8283. if (BuffSize > MAXUSHORT) // Make sure BuffSize fits in a USHORT
  8284. {
  8285. BuffSize = MAXUSHORT; // Recalculate BuffSize and AllocatedCount
  8286. AllocatedCount = (BuffSize - sizeof(ADAPTER_STATUS)) / NameSize;
  8287. }
  8288. #endif // VXD
  8289. #ifdef VXD
  8290. pAdapterStatus = NbtAllocMem((USHORT)BuffSize,NBT_TAG('O'));
  8291. #else
  8292. pAdapterStatus = NbtAllocMem(BuffSize,NBT_TAG('O'));
  8293. #endif
  8294. if (!pAdapterStatus)
  8295. {
  8296. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  8297. return(STATUS_INSUFFICIENT_RESOURCES);
  8298. }
  8299. // Fill out the adapter status structure with zeros first
  8300. CTEZeroMemory((PVOID)pAdapterStatus,BuffSize);
  8301. //
  8302. // Fill in the MAC address
  8303. //
  8304. pMacAddr = &pDeviceContext->MacAddress.Address[0];
  8305. CTEMemCopy(&pAdapterStatus->adapter_address[0], pMacAddr, sizeof(tMAC_ADDRESS));
  8306. pAdapterStatus->rev_major = 0x03;
  8307. pAdapterStatus->adapter_type = 0xFE; // pretend it is an ethernet adapter
  8308. //
  8309. // in the VXD land limit the number of Ncbs to 64
  8310. //
  8311. #ifndef VXD
  8312. MaxAllowed = 0xFFFF;
  8313. pAdapterStatus->max_cfg_sess = (USHORT)MaxAllowed;
  8314. pAdapterStatus->max_sess = (USHORT)MaxAllowed;
  8315. #else
  8316. MaxAllowed = 64;
  8317. pAdapterStatus->max_cfg_sess = pDeviceContext->cMaxSessions;
  8318. pAdapterStatus->max_sess = pDeviceContext->cMaxSessions;
  8319. #endif
  8320. pAdapterStatus->free_ncbs = (USHORT)MaxAllowed;
  8321. pAdapterStatus->max_cfg_ncbs = (USHORT)MaxAllowed;
  8322. pAdapterStatus->max_ncbs = (USHORT)MaxAllowed;
  8323. pAdapterStatus->max_dgram_size = MAX_NBT_DGRAM_SIZE;
  8324. pAdapterStatus->max_sess_pkt_size = 0xffff;
  8325. // get the address of the name buffer at the end of the adapter status
  8326. // structure so we can copy the names into this area.
  8327. pNameBuffer = (PNAME_BUFFER)((ULONG_PTR)pAdapterStatus + sizeof(ADAPTER_STATUS));
  8328. ActualCount = 0;
  8329. j = 0;
  8330. if (Location == NBT_LOCAL)
  8331. {
  8332. pEntry = pHead = &NbtConfig.AddressHead;
  8333. }
  8334. else
  8335. {
  8336. pEntry = pHead = &pHashTable->Bucket[0];
  8337. }
  8338. while (AllocatedCount)
  8339. {
  8340. if (Location == NBT_LOCAL)
  8341. {
  8342. // ***** LOCAL HASH TABLE QUERY *****
  8343. // get out of while if we reach the end of the list
  8344. if ((pEntry = pEntry->Flink) == pHead)
  8345. {
  8346. break;
  8347. }
  8348. pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
  8349. pNameAddr = pAddressEle->pNameAddr;
  8350. //
  8351. // skip the broadcast name and any permanent names that are
  8352. // registered as quick names(i.e. not registered on the net).
  8353. //
  8354. if ((pAddressEle->pNameAddr->Name[0] == '*') ||
  8355. (pAddressEle->pNameAddr->NameTypeState & NAMETYPE_QUICK) ||
  8356. (!(pAddressEle->pNameAddr->AdapterMask & pDeviceContext->AdapterMask))) // This Device only
  8357. {
  8358. continue;
  8359. }
  8360. }
  8361. else
  8362. {
  8363. // ***** REMOTE HASH TABLE QUERY *****
  8364. //
  8365. // See if we have reached the end of the HashTable
  8366. //
  8367. if (j == pHashTable->lNumBuckets)
  8368. {
  8369. break;
  8370. }
  8371. //
  8372. // See if we have reached the last entry in the HashBucket
  8373. //
  8374. if ((pEntry = pEntry->Flink) == pHead)
  8375. {
  8376. pEntry = pHead = &pHashTable->Bucket[++j];
  8377. continue;
  8378. }
  8379. // for the remote table, skip over scope records.
  8380. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  8381. // don't return scope records or resolving records
  8382. //
  8383. if ((pNameAddr->NameTypeState & NAMETYPE_SCOPE) ||
  8384. (!(pNameAddr->NameTypeState & STATE_RESOLVED)) ||
  8385. (!(pNameAddr->AdapterMask & pDeviceContext->AdapterMask)))
  8386. {
  8387. continue;
  8388. }
  8389. //
  8390. // the remote cache query has a different structure that includes
  8391. // the ip address. Return the ip address to the caller.
  8392. //
  8393. IpAddress = 0;
  8394. PickBestAddress (pNameAddr, pDeviceContext, &IpAddress);
  8395. ((tREMOTE_CACHE *)pNameBuffer)->IpAddress = IpAddress;
  8396. // preloaded entries do not timeout
  8397. //
  8398. if (pNameAddr->NameTypeState & PRELOADED)
  8399. {
  8400. Ttl = 0xFFFFFFFF;
  8401. }
  8402. else
  8403. {
  8404. Ttl = ((pNameAddr->TimeOutCount+1) * REMOTE_HASH_TIMEOUT)/1000;
  8405. }
  8406. ((tREMOTE_CACHE *)pNameBuffer)->Ttl = Ttl;
  8407. }
  8408. pNameBuffer->name_flags = (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ? UNIQUE_NAME : GROUP_NAME;
  8409. switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
  8410. {
  8411. default:
  8412. case STATE_RESOLVED:
  8413. pNameBuffer->name_flags |= REGISTERED;
  8414. break;
  8415. case STATE_CONFLICT:
  8416. pNameBuffer->name_flags |= DUPLICATE;
  8417. break;
  8418. case STATE_RELEASED:
  8419. pNameBuffer->name_flags |= DEREGISTERED;
  8420. break;
  8421. case STATE_RESOLVING:
  8422. pNameBuffer->name_flags |= REGISTERING;
  8423. break;
  8424. }
  8425. //
  8426. // name number 0 corresponds to perm.name name, so start from 1
  8427. //
  8428. pNameBuffer->name_num = (UCHAR) (ActualCount+1);
  8429. CTEMemCopy(pNameBuffer->name,pNameAddr->Name,NETBIOS_NAME_SIZE);
  8430. if (Location == NBT_LOCAL)
  8431. {
  8432. pNameBuffer++;
  8433. }
  8434. else
  8435. {
  8436. ((tREMOTE_CACHE *)pNameBuffer)++;
  8437. }
  8438. AllocatedCount--;
  8439. ActualCount++;
  8440. }
  8441. //
  8442. // ReCalculate the new BuffSize based on the number of names
  8443. // we actually copied
  8444. //
  8445. BuffSize = sizeof(ADAPTER_STATUS) + ActualCount*NameSize;
  8446. //
  8447. // Is our status buffer size greater then the user's buffer?
  8448. // If the user buffer is expected to overflow, then
  8449. // set the name_count to the maximum number of valid names
  8450. // in the buffer
  8451. //
  8452. if (BuffSize > *pSize)
  8453. {
  8454. //
  8455. // Recalc how many names will fit
  8456. //
  8457. if (*pSize <= sizeof(ADAPTER_STATUS))
  8458. {
  8459. ActualCount = 0;
  8460. }
  8461. else
  8462. {
  8463. ActualCount = (*pSize - sizeof(ADAPTER_STATUS)) / NameSize;
  8464. }
  8465. }
  8466. pAdapterStatus->name_count = (USHORT)ActualCount;
  8467. //
  8468. // return the ptr to this wonderful structure of goodies
  8469. //
  8470. *ppAdapterStatus = (PVOID)pAdapterStatus;
  8471. *pSize = BuffSize;
  8472. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  8473. return (STATUS_SUCCESS);
  8474. }
  8475. //----------------------------------------------------------------------------
  8476. NTSTATUS
  8477. NbtQueryConnectionList(
  8478. IN tDEVICECONTEXT *pDeviceContext,
  8479. OUT PVOID *ppConnList,
  8480. IN OUT PLONG pSize
  8481. )
  8482. /*++
  8483. Routine Description
  8484. This routine creates a list of netbios connections and returns them to the
  8485. client. It is used by the "NbtStat" console application.
  8486. Arguments:
  8487. Return Values:
  8488. TDI_STATUS - status of the request
  8489. --*/
  8490. {
  8491. CTELockHandle OldIrq1;
  8492. CTELockHandle OldIrq2;
  8493. CTELockHandle OldIrq3;
  8494. LONG Count;
  8495. LONG i;
  8496. LONG BuffSize;
  8497. PLIST_ENTRY pEntry;
  8498. PLIST_ENTRY pEntry1;
  8499. PLIST_ENTRY pEntry2;
  8500. PLIST_ENTRY pHead;
  8501. PLIST_ENTRY pHead1;
  8502. PLIST_ENTRY pHead2;
  8503. ULONG NameSize;
  8504. tCONNECTIONS *pCons;
  8505. tCONNECTION_LIST *pConnList;
  8506. tADDRESSELE *pAddressEle;
  8507. tLOWERCONNECTION *pLowerConn;
  8508. tCONNECTELE *pConnEle;
  8509. tCLIENTELE *pClient;
  8510. NTSTATUS status = STATUS_SUCCESS; // default
  8511. // locking the joint lock is enough to prevent new addresses from being
  8512. // added to the list while we count the list.
  8513. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  8514. // go through the list of addresses, then the list of clients on each
  8515. // address and then the list of connection that are in use and those that
  8516. // are currently Listening.
  8517. //
  8518. Count = 0;
  8519. pHead = &NbtConfig.AddressHead;
  8520. pEntry = pHead->Flink;
  8521. while (pEntry != pHead)
  8522. {
  8523. pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
  8524. CTESpinLock(pAddressEle,OldIrq2);
  8525. pHead1 = &pAddressEle->ClientHead;
  8526. pEntry1 = pHead1->Flink;
  8527. while (pEntry1 != pHead1)
  8528. {
  8529. pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage);
  8530. pEntry1 = pEntry1->Flink;
  8531. CTESpinLock(pClient,OldIrq3);
  8532. pHead2 = &pClient->ConnectActive;
  8533. pEntry2 = pHead2->Flink;
  8534. while (pEntry2 != pHead2)
  8535. {
  8536. // count the connections in use
  8537. pEntry2 = pEntry2->Flink;
  8538. Count++;
  8539. }
  8540. pHead2 = &pClient->ListenHead;
  8541. pEntry2 = pHead2->Flink;
  8542. while (pEntry2 != pHead2)
  8543. {
  8544. // count the connections listening
  8545. pEntry2 = pEntry2->Flink;
  8546. Count++;
  8547. }
  8548. CTESpinFree(pClient,OldIrq3);
  8549. }
  8550. CTESpinFree(pAddressEle,OldIrq2);
  8551. pEntry = pEntry->Flink;
  8552. }
  8553. NameSize = sizeof(tCONNECTIONS);
  8554. // Allocate Memory for the adapter status
  8555. BuffSize = sizeof(tCONNECTION_LIST) + Count*NameSize;
  8556. pConnList = NbtAllocMem(BuffSize,NBT_TAG('P'));
  8557. if (!pConnList)
  8558. {
  8559. CTESpinFree(&NbtConfig.JointLock, OldIrq1);
  8560. return(STATUS_INSUFFICIENT_RESOURCES);
  8561. }
  8562. //
  8563. // Initialize the adapter status structure
  8564. //
  8565. CTEZeroMemory ((PVOID)pConnList, BuffSize);
  8566. pConnList->ConnectionCount = Count;
  8567. *ppConnList = (PVOID)pConnList;
  8568. if (Count == 0)
  8569. {
  8570. //
  8571. // We are done!
  8572. //
  8573. *pSize = BuffSize;
  8574. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  8575. return status;
  8576. }
  8577. // get the address of the Connection List buffer at the end of the
  8578. // structure so we can copy the Connection info into this area.
  8579. pCons = pConnList->ConnList;
  8580. pHead = &NbtConfig.AddressHead;
  8581. pEntry = pHead->Flink;
  8582. i = 0;
  8583. while (pEntry != pHead)
  8584. {
  8585. pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
  8586. pEntry = pEntry->Flink;
  8587. CTESpinLock(pAddressEle,OldIrq2);
  8588. pHead1 = &pAddressEle->ClientHead;
  8589. pEntry1 = pHead1->Flink;
  8590. while (pEntry1 != pHead1)
  8591. {
  8592. pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage);
  8593. pEntry1 = pEntry1->Flink;
  8594. CTESpinLock(pClient,OldIrq3);
  8595. pHead2 = &pClient->ConnectActive;
  8596. pEntry2 = pHead2->Flink;
  8597. while (pEntry2 != pHead2)
  8598. {
  8599. // count the connections in use
  8600. pConnEle = CONTAINING_RECORD(pEntry2,tCONNECTELE,Linkage);
  8601. if (pConnEle->pDeviceContext == pDeviceContext)
  8602. {
  8603. CTEMemCopy(pCons->LocalName,
  8604. pConnEle->pClientEle->pAddress->pNameAddr->Name,
  8605. NETBIOS_NAME_SIZE);
  8606. pLowerConn = pConnEle->pLowerConnId;
  8607. if (pLowerConn)
  8608. {
  8609. pCons->SrcIpAddr = pLowerConn->SrcIpAddr;
  8610. pCons->Originator = (UCHAR)pLowerConn->bOriginator;
  8611. #ifndef VXD
  8612. pCons->BytesRcvd = *(PLARGE_INTEGER)&pLowerConn->BytesRcvd;
  8613. pCons->BytesSent = *(PLARGE_INTEGER)&pLowerConn->BytesSent;
  8614. #else
  8615. pCons->BytesRcvd = pLowerConn->BytesRcvd;
  8616. pCons->BytesSent = pLowerConn->BytesSent;
  8617. #endif
  8618. CTEMemCopy(pCons->RemoteName,pConnEle->RemoteName,NETBIOS_NAME_SIZE);
  8619. }
  8620. pCons->State = pConnEle->state;
  8621. i++;
  8622. pCons++;
  8623. if (i >= Count)
  8624. {
  8625. break;
  8626. }
  8627. }
  8628. pEntry2 = pEntry2->Flink;
  8629. }
  8630. if (i >= Count)
  8631. {
  8632. CTESpinFree(pClient,OldIrq3);
  8633. break;
  8634. }
  8635. //
  8636. // now for the Listens
  8637. //
  8638. pHead2 = &pClient->ListenHead;
  8639. pEntry2 = pHead2->Flink;
  8640. while (pEntry2 != pHead2)
  8641. {
  8642. tLISTENREQUESTS *pListenReq;
  8643. // count the connections listening on this Device
  8644. pListenReq = CONTAINING_RECORD(pEntry2,tLISTENREQUESTS,Linkage);
  8645. pConnEle = (tCONNECTELE *)pListenReq->pConnectEle;
  8646. pEntry2 = pEntry2->Flink;
  8647. if (pConnEle->pDeviceContext == pDeviceContext)
  8648. {
  8649. CTEMemCopy(pCons->LocalName,
  8650. pConnEle->pClientEle->pAddress->pNameAddr->Name,
  8651. NETBIOS_NAME_SIZE);
  8652. pCons->State = LISTENING;
  8653. i++;
  8654. pCons++;
  8655. if (i >= Count)
  8656. {
  8657. break;
  8658. }
  8659. }
  8660. }
  8661. CTESpinFree(pClient,OldIrq3);
  8662. if (i >= Count)
  8663. {
  8664. break;
  8665. }
  8666. }
  8667. CTESpinFree(pAddressEle,OldIrq2);
  8668. if (i >= Count)
  8669. {
  8670. break;
  8671. }
  8672. }
  8673. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  8674. //
  8675. // return the ptr to this wonderful structure of goodies
  8676. //
  8677. Count = i;
  8678. BuffSize = sizeof(tCONNECTION_LIST) + Count*NameSize;
  8679. //
  8680. // Is our status buffer size greater then the user's buffer?
  8681. // Set the Count value based on the number of connections
  8682. // actually being returned
  8683. //
  8684. if (BuffSize > *pSize)
  8685. {
  8686. //
  8687. // Recalc how many names will fit
  8688. // tCONNECTION_LIST already contains space for 1 tCONNECTION
  8689. // structure, but we will not include it in our calculations
  8690. // -- rather we will leave it as an overflow check
  8691. //
  8692. if (*pSize <= sizeof(tCONNECTION_LIST))
  8693. {
  8694. Count = 0 ;
  8695. }
  8696. else
  8697. {
  8698. Count = (*pSize - sizeof(tCONNECTION_LIST)) / NameSize ;
  8699. }
  8700. }
  8701. pConnList->ConnectionCount = Count;
  8702. *pSize = BuffSize;
  8703. return status;
  8704. }
  8705. //----------------------------------------------------------------------------
  8706. VOID
  8707. DelayedNbtResyncRemoteCache(
  8708. IN PVOID Unused1,
  8709. IN PVOID Unused2,
  8710. IN PVOID Unused3,
  8711. IN tDEVICECONTEXT *Unused4
  8712. )
  8713. /*++
  8714. Routine Description
  8715. This routine creates a list of netbios connections and returns them to the
  8716. client. It is used by the "NbtStat" console application.
  8717. It cannot be called with any lock or NbtConfig.Resource held!
  8718. Arguments:
  8719. Return Values:
  8720. TDI_STATUS - status of the request
  8721. --*/
  8722. {
  8723. tTIMERQENTRY TimerEntry = {0};
  8724. LONG i;
  8725. LONG lRetcode;
  8726. PUCHAR LmHostsPath;
  8727. CTEPagedCode();
  8728. //
  8729. // calling this routine N+1 times should remove all names from the remote
  8730. // hash table - N to count down the TimedOutCount to zero and then
  8731. // one more to remove the name
  8732. //
  8733. RemoteHashTimeout(NbtConfig.pRemoteHashTbl,NULL,&TimerEntry);
  8734. RemovePreloads(); // now remove any preloaded entries
  8735. // now reload the preloads
  8736. #ifndef VXD
  8737. //
  8738. // The NbtConfig.pLmHosts path can change if the registry is
  8739. // read during this interval
  8740. // We cannot acquire the ResourceLock here since reading the
  8741. // LmHosts file might result in File operations + network reads
  8742. // that could cause a deadlock (Worker threads / ResourceLock)!
  8743. // Best solution at this time is to copy the path onto a local
  8744. // buffer under the Resource lock, and then try to read the file!
  8745. // Bug # 247429
  8746. //
  8747. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  8748. if ((!NbtConfig.pLmHosts) ||
  8749. (!(LmHostsPath = NbtAllocMem ((strlen(NbtConfig.pLmHosts)+1), NBT_TAG2('23')))))
  8750. {
  8751. CTEExReleaseResource(&NbtConfig.Resource);
  8752. return;
  8753. }
  8754. CTEMemCopy (LmHostsPath, NbtConfig.pLmHosts, (strlen(NbtConfig.pLmHosts)+1));
  8755. CTEExReleaseResource(&NbtConfig.Resource);
  8756. lRetcode = PrimeCache(LmHostsPath, NULL, MAX_RECURSE_DEPTH, NULL);
  8757. CTEMemFree(LmHostsPath);
  8758. return;
  8759. #else
  8760. lRetcode = PrimeCache(NbtConfig.pLmHosts, NULL, MAX_RECURSE_DEPTH, NULL);
  8761. //
  8762. // check if things didn't go well (InDos was set etc.)
  8763. //
  8764. if (lRetcode == -1)
  8765. {
  8766. return (STATUS_UNSUCCESSFUL);
  8767. }
  8768. return(STATUS_SUCCESS);
  8769. #endif // !VXD
  8770. }
  8771. //----------------------------------------------------------------------------
  8772. NTSTATUS
  8773. NbtQueryBcastVsWins(
  8774. IN tDEVICECONTEXT *pDeviceContext,
  8775. OUT PVOID *ppBuffer,
  8776. IN OUT PLONG pSize
  8777. )
  8778. /*++
  8779. Routine Description
  8780. This routine creates a list of netbios names that have been resolved
  8781. via broadcast and returns them along with the count of names resolved
  8782. via WINS and via broadcast. It lets a user know which names are not
  8783. in WINS and the relative frequency of "misses" with WINS that resort
  8784. to broadcast.
  8785. Arguments:
  8786. Return Values:
  8787. TDI_STATUS - status of the request
  8788. --*/
  8789. {
  8790. tNAMESTATS_INFO *pStats;
  8791. LONG Count;
  8792. tNAME *pDest;
  8793. tNAME *pSrc;
  8794. LONG Index;
  8795. //
  8796. // Is our status buffer size greater then the user's buffer?
  8797. //
  8798. if ( sizeof(tNAMESTATS_INFO) > *pSize )
  8799. {
  8800. return (STATUS_BUFFER_TOO_SMALL);
  8801. }
  8802. pStats = NbtAllocMem(sizeof(tNAMESTATS_INFO),NBT_TAG('Q'));
  8803. if ( !pStats )
  8804. {
  8805. return(STATUS_INSUFFICIENT_RESOURCES);
  8806. }
  8807. // Fill out the adapter status structure with zeros first
  8808. CTEZeroMemory((PVOID)pStats,sizeof(tNAMESTATS_INFO));
  8809. CTEMemCopy(pStats,&NameStatsInfo,FIELD_OFFSET(tNAMESTATS_INFO,NamesReslvdByBcast) );
  8810. //
  8811. // re-order the names so that names are returned in a list of newest to
  8812. // oldest down the list.
  8813. //
  8814. Count = 0;
  8815. Index = NameStatsInfo.Index;
  8816. pDest = &pStats->NamesReslvdByBcast[SIZE_RESOLVD_BY_BCAST_CACHE-1];
  8817. while (Count < SIZE_RESOLVD_BY_BCAST_CACHE)
  8818. {
  8819. pSrc = &NameStatsInfo.NamesReslvdByBcast[Index++];
  8820. CTEMemCopy(pDest,pSrc,NETBIOS_NAME_SIZE);
  8821. pDest--;
  8822. if (Index >= SIZE_RESOLVD_BY_BCAST_CACHE)
  8823. {
  8824. Index = 0;
  8825. pSrc = NameStatsInfo.NamesReslvdByBcast;
  8826. }
  8827. else
  8828. {
  8829. pSrc++;
  8830. }
  8831. Count++;
  8832. }
  8833. //
  8834. // return the ptr to this wonderful structure of goodies
  8835. //
  8836. *ppBuffer = (PVOID)pStats;
  8837. *pSize = sizeof(tNAMESTATS_INFO);
  8838. return STATUS_SUCCESS;
  8839. }
  8840. ULONG
  8841. RemoveCachedAddresses(
  8842. tDEVICECONTEXT *pDeviceContext
  8843. )
  8844. {
  8845. LONG i;
  8846. CTELockHandle OldIrq;
  8847. tNAMEADDR *pNameAddr;
  8848. tHASHTABLE *pHashTable;
  8849. PLIST_ENTRY pHead;
  8850. PLIST_ENTRY pEntry;
  8851. ULONG Count = 0;
  8852. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  8853. //
  8854. // go through the Remote table removing addresses resolved on this interface
  8855. //
  8856. pHashTable = NbtConfig.pRemoteHashTbl;
  8857. for (i=0; i < pHashTable->lNumBuckets; i++)
  8858. {
  8859. pHead = &pHashTable->Bucket[i];
  8860. pEntry = pHead->Flink;
  8861. while (pEntry != pHead)
  8862. {
  8863. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  8864. pEntry = pEntry->Flink;
  8865. //
  8866. // do not delete scope entries, and do not delete names that
  8867. // that are still resolving, and do not delete names that are
  8868. // being used by someone (refcount > 1)
  8869. //
  8870. if (pNameAddr->RemoteCacheLen > pDeviceContext->AdapterNumber)
  8871. {
  8872. pNameAddr->pRemoteIpAddrs[pDeviceContext->AdapterNumber].IpAddress = 0;
  8873. if (pNameAddr->pRemoteIpAddrs[pDeviceContext->AdapterNumber].pOrigIpAddrs)
  8874. {
  8875. CTEMemFree(pNameAddr->pRemoteIpAddrs[pDeviceContext->AdapterNumber].pOrigIpAddrs);
  8876. pNameAddr->pRemoteIpAddrs[pDeviceContext->AdapterNumber].pOrigIpAddrs = NULL;
  8877. }
  8878. pNameAddr->AdapterMask &= ~pDeviceContext->AdapterMask;
  8879. #if DBG
  8880. /*
  8881. // MALAM_FIX -- Preloaded entries have 2 References!
  8882. if ((!pNameAddr->AdapterMask) &&
  8883. (!(pNameAddr->NameTypeState & NAMETYPE_SCOPE)))
  8884. {
  8885. RemoveEntryList (&pNameAddr->Linkage);
  8886. InsertTailList(&NbtConfig.StaleRemoteNames, &pNameAddr->Linkage);
  8887. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  8888. }
  8889. */
  8890. #endif // DBG
  8891. Count++;
  8892. }
  8893. }
  8894. }
  8895. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  8896. return (Count);
  8897. }
  8898. VOID
  8899. NbtAddressChangeResyncCacheTimeout(
  8900. PVOID pContext,
  8901. PVOID pContext2,
  8902. tTIMERQENTRY *pTimerQEntry
  8903. )
  8904. {
  8905. if (!pTimerQEntry)
  8906. {
  8907. return;
  8908. }
  8909. NTQueueToWorkerThread(NULL, DelayedNbtResyncRemoteCache, NULL, NULL, NULL, NULL, FALSE);
  8910. return;
  8911. }
  8912. #ifndef VXD
  8913. //----------------------------------------------------------------------------
  8914. VOID
  8915. NbtCheckSetNameAdapterInfo(
  8916. tDEVICECONTEXT *pDeviceContext,
  8917. ULONG IpAddress
  8918. )
  8919. {
  8920. LONG i;
  8921. CTELockHandle OldIrq;
  8922. tTIMERQENTRY *pTimerEntry;
  8923. tNAMEADDR *pNameAddr;
  8924. tHASHTABLE *pHashTable;
  8925. PLIST_ENTRY pHead, pEntry;
  8926. BOOLEAN fStartRefresh = FALSE;
  8927. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  8928. if (pWinsInfo)
  8929. {
  8930. if (IpAddress)
  8931. {
  8932. //
  8933. // If there is no IP address, or the new IP address is the one Wins had preferred,
  8934. // use it
  8935. //
  8936. if (((IpAddress == pWinsInfo->IpAddress) || (!pWinsInfo->pDeviceContext)) &&
  8937. (NBT_VERIFY_HANDLE (pDeviceContext, NBT_VERIFY_DEVCONTEXT)))
  8938. {
  8939. pWinsInfo->pDeviceContext = pDeviceContext;
  8940. }
  8941. }
  8942. else
  8943. {
  8944. if (pDeviceContext == pWinsInfo->pDeviceContext)
  8945. {
  8946. pWinsInfo->pDeviceContext = GetDeviceWithIPAddress(pWinsInfo->IpAddress);
  8947. }
  8948. }
  8949. }
  8950. //
  8951. // For a Netbiosless device notification, we are done!
  8952. //
  8953. if (pDeviceContext->DeviceType == NBT_DEVICE_NETBIOSLESS)
  8954. {
  8955. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  8956. return;
  8957. }
  8958. if (IpAddress == 0)
  8959. {
  8960. //
  8961. // See if there were any names in conflict which we need to refresh!
  8962. //
  8963. pHashTable = NbtConfig.pLocalHashTbl;
  8964. for (i=0; i < pHashTable->lNumBuckets; i++)
  8965. {
  8966. pHead = &pHashTable->Bucket[i];
  8967. pEntry = pHead->Flink;
  8968. while (pEntry != pHead)
  8969. {
  8970. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  8971. pEntry = pEntry->Flink;
  8972. if (pNameAddr->ConflictMask & pDeviceContext->AdapterMask)
  8973. {
  8974. //
  8975. // Zero out the Conflicting adapter mask
  8976. // Restart Refreshing this name if there are no more
  8977. // adapters on which the name went into conflict
  8978. //
  8979. pNameAddr->ConflictMask &= (~pDeviceContext->AdapterMask);
  8980. if (!(pNameAddr->ConflictMask))
  8981. {
  8982. pNameAddr->RefreshMask = 0;
  8983. fStartRefresh = TRUE;
  8984. }
  8985. }
  8986. }
  8987. }
  8988. }
  8989. else
  8990. {
  8991. if (NodeType & BNODE)
  8992. {
  8993. //
  8994. // Stop the RefreshTimer if it is running!
  8995. //
  8996. if (pTimerEntry = NbtConfig.pRefreshTimer)
  8997. {
  8998. NbtConfig.pRefreshTimer = NULL;
  8999. StopTimer (pTimerEntry, NULL, NULL);
  9000. }
  9001. }
  9002. else
  9003. {
  9004. fStartRefresh = TRUE;
  9005. }
  9006. }
  9007. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9008. if (fStartRefresh)
  9009. {
  9010. //
  9011. // ReRegister all the local names on this device with the WINS server
  9012. //
  9013. ReRegisterLocalNames(pDeviceContext, FALSE);
  9014. }
  9015. }
  9016. #endif // !VXD
  9017. #ifndef REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
  9018. //----------------------------------------------------------------------------
  9019. VOID
  9020. DelayedNbtProcessDhcpRequests(
  9021. PVOID Unused1,
  9022. PVOID Unused2,
  9023. PVOID Unused3,
  9024. PVOID pDevice)
  9025. /*++
  9026. Routine Description:
  9027. Process each DHCP requests queued by NbtNewDhcpAddress
  9028. Arguments:
  9029. Return Value:
  9030. NONE
  9031. --*/
  9032. {
  9033. tDEVICECONTEXT *pDeviceContext;
  9034. CTELockHandle OldIrq;
  9035. enum eTDI_ACTION action;
  9036. pDeviceContext = (tDEVICECONTEXT*)pDevice;
  9037. CTESpinLock(pDeviceContext, OldIrq);
  9038. action = pDeviceContext->DelayedNotification;
  9039. ASSERT(action == NBT_TDI_REGISTER || action == NBT_TDI_NOACTION);
  9040. if (action != NBT_TDI_NOACTION) {
  9041. pDeviceContext->DelayedNotification = NBT_TDI_BUSY;
  9042. }
  9043. CTESpinFree(pDeviceContext, OldIrq);
  9044. if (action != NBT_TDI_NOACTION) {
  9045. NbtNotifyTdiClients (pDeviceContext, action);
  9046. CTESpinLock(pDeviceContext, OldIrq);
  9047. pDeviceContext->DelayedNotification = NBT_TDI_NOACTION;
  9048. CTESpinFree(pDeviceContext, OldIrq);
  9049. KeSetEvent(&pDeviceContext->DelayedNotificationCompleteEvent, 0, FALSE);
  9050. }
  9051. //
  9052. // Call this routine at PASSIVE_LEVEL
  9053. //
  9054. NbtDownBootCounter();
  9055. }
  9056. VOID
  9057. StartProcessNbtDhcpRequests(
  9058. PVOID pContext,
  9059. PVOID pContext2,
  9060. tTIMERQENTRY *pTimerQEntry
  9061. )
  9062. {
  9063. /*
  9064. * if pTimerQEntry == NULL, we are being called from StopTimer which is called by NbtDestroyDevice
  9065. * DelayedNbtDeleteDevice will take care of notifying the clients and proper cleanup.
  9066. */
  9067. if (pTimerQEntry) {
  9068. tDEVICECONTEXT *pDeviceContext;
  9069. pDeviceContext = (tDEVICECONTEXT*)(pTimerQEntry->pDeviceContext);
  9070. if (!NT_SUCCESS(NTQueueToWorkerThread(NULL, DelayedNbtProcessDhcpRequests,
  9071. NULL, NULL, NULL, (tDEVICECONTEXT*)pTimerQEntry->pDeviceContext, FALSE))) {
  9072. pDeviceContext->DelayedNotification = NBT_TDI_NOACTION;
  9073. KeSetEvent(&pDeviceContext->DelayedNotificationCompleteEvent, 0, FALSE);
  9074. NbtDownBootCounter();
  9075. }
  9076. } else {
  9077. NbtDownBootCounter();
  9078. }
  9079. }
  9080. //----------------------------------------------------------------------------
  9081. NTSTATUS
  9082. NbtQueueTdiNotification (
  9083. tDEVICECONTEXT *pDeviceContext,
  9084. enum eTDI_ACTION action
  9085. )
  9086. /*++
  9087. Routine Description:
  9088. 1. Queue the DHCP address notifications into NbtConfig.DhcpNewAddressQList.
  9089. 2. Start the worker thread if needed.
  9090. Arguments:
  9091. Return Value:
  9092. NTSTATUS
  9093. --*/
  9094. {
  9095. NTSTATUS status;
  9096. CTELockHandle OldIrq1, OldIrq2;
  9097. if (NbtConfig.DhcpProcessingDelay == 0) {
  9098. NbtNotifyTdiClients (pDeviceContext, action);
  9099. return STATUS_SUCCESS;
  9100. }
  9101. if (action == NBT_TDI_DEREGISTER) {
  9102. /*
  9103. * This should be done synchronously
  9104. */
  9105. CTESpinLock(&NbtConfig.JointLock, OldIrq1);
  9106. CTESpinLock(pDeviceContext, OldIrq2);
  9107. if (pDeviceContext->DelayedNotification != NBT_TDI_BUSY) {
  9108. pDeviceContext->DelayedNotification = NBT_TDI_NOACTION;
  9109. KeSetEvent(&pDeviceContext->DelayedNotificationCompleteEvent, 0, FALSE);
  9110. } else {
  9111. ASSERT(!KeReadStateEvent(&pDeviceContext->DelayedNotificationCompleteEvent));
  9112. }
  9113. CTESpinFree(pDeviceContext, OldIrq2);
  9114. CTESpinFree(&NbtConfig.JointLock, OldIrq1);
  9115. status = KeWaitForSingleObject(
  9116. &pDeviceContext->DelayedNotificationCompleteEvent,
  9117. Executive,
  9118. KernelMode,
  9119. FALSE,
  9120. NULL
  9121. );
  9122. ASSERT(status == STATUS_WAIT_0);
  9123. NbtNotifyTdiClients (pDeviceContext, NBT_TDI_DEREGISTER);
  9124. return STATUS_SUCCESS;
  9125. }
  9126. /*
  9127. * Queue NBT_TDI_REGISTER
  9128. */
  9129. ASSERT(action == NBT_TDI_REGISTER);
  9130. CTESpinLock(&NbtConfig.JointLock, OldIrq1);
  9131. CTESpinLock(pDeviceContext, OldIrq2);
  9132. if (pDeviceContext->DelayedNotification != NBT_TDI_NOACTION) {
  9133. /*
  9134. * Do nothing because another indication is going on
  9135. */
  9136. ASSERT(pDeviceContext->DelayedNotification == NBT_TDI_REGISTER ||
  9137. pDeviceContext->DelayedNotification == NBT_TDI_BUSY);
  9138. CTESpinFree(pDeviceContext, OldIrq2);
  9139. CTESpinFree(&NbtConfig.JointLock, OldIrq1);
  9140. return STATUS_SUCCESS;
  9141. }
  9142. status = StartTimer (StartProcessNbtDhcpRequests, NbtConfig.DhcpProcessingDelay,
  9143. NULL, NULL, NULL, NULL, pDeviceContext, NULL, 0, TRUE);
  9144. if (NT_SUCCESS(status)) {
  9145. KeResetEvent(&pDeviceContext->DelayedNotificationCompleteEvent);
  9146. pDeviceContext->DelayedNotification = action;
  9147. NbtUpBootCounter();
  9148. }
  9149. CTESpinFree(pDeviceContext, OldIrq2);
  9150. CTESpinFree(&NbtConfig.JointLock, OldIrq1);
  9151. if (!NT_SUCCESS(status)) {
  9152. NbtNotifyTdiClients (pDeviceContext, action);
  9153. }
  9154. return STATUS_SUCCESS;
  9155. }
  9156. #endif // REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
  9157. //----------------------------------------------------------------------------
  9158. NTSTATUS
  9159. NbtNewDhcpAddress(
  9160. tDEVICECONTEXT *pDeviceContext,
  9161. ULONG IpAddress,
  9162. ULONG SubnetMask)
  9163. /*++
  9164. Routine Description:
  9165. This routine processes a DHCP request to set a new ip address
  9166. for this node. Dhcp may pass in a zero for the ip address first
  9167. meaning that it is about to change the IP address, so all connections
  9168. should be shut down.
  9169. It closes all connections with the transport and all addresses. Then
  9170. It reopens them at the new ip address.
  9171. Note for NETBIOSLESS:
  9172. I have modeled a disabled adapter after an adapter with no address. I considered
  9173. not creating the device, but then, without the device, there is no handle
  9174. for setup to contact the driver in order to enable it again.
  9175. Arguments:
  9176. Return Value:
  9177. none
  9178. --*/
  9179. {
  9180. NTSTATUS status;
  9181. BOOLEAN Attached;
  9182. ULONG Count, i;
  9183. CTEPagedCode();
  9184. CHECK_PTR(pDeviceContext);
  9185. #ifdef _NETBIOSLESS
  9186. if ( (!pDeviceContext->NetbiosEnabled) && (IpAddress != 0) )
  9187. {
  9188. IF_DBG(NBT_DEBUG_PNP_POWER)
  9189. KdPrint(("NbtNewDhcpAddr: %wZ disabling address\n",&pDeviceContext->ExportName));
  9190. IpAddress = 0;
  9191. SubnetMask = 0;
  9192. }
  9193. #endif
  9194. // grab the resource that synchronizes opening addresses and connections.
  9195. // to prevent the client from doing anything for a while
  9196. //
  9197. IF_DBG(NBT_DEBUG_PNP_POWER)
  9198. {
  9199. KdPrint(("Nbt.NbtNewDhcpAddress: %d.%d.%d.%d\n",
  9200. (IpAddress) & 0xFF,
  9201. (IpAddress>>8) & 0xFF,
  9202. (IpAddress>>16) & 0xFF,
  9203. (IpAddress>>24) & 0xFF));
  9204. }
  9205. if (IpAddress == 0)
  9206. {
  9207. if (pDeviceContext->IpAddress)
  9208. {
  9209. NbtTrace(NBT_TRACE_PNP, ("remove %!ipaddr! from device %p %Z",
  9210. pDeviceContext->IpAddress, pDeviceContext, &pDeviceContext->BindName));
  9211. #ifdef VXD
  9212. //
  9213. // The permanent name is a function of the MAC address so remove
  9214. // it since the Adapter is losing its Ip address
  9215. //
  9216. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  9217. NbtRemovePermanentName(pDeviceContext);
  9218. #else
  9219. CloseAddressesWithTransport(pDeviceContext);
  9220. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  9221. #endif // VXD
  9222. //
  9223. // Dhcp is has passed down a null IP address meaning that it has
  9224. // lost the lease on the previous address, so close all connections
  9225. // to the transport - pLowerConn.
  9226. //
  9227. DisableInboundConnections (pDeviceContext);
  9228. #ifndef VXD
  9229. CTEExReleaseResource(&NbtConfig.Resource);
  9230. NbtCheckSetNameAdapterInfo (pDeviceContext, IpAddress);
  9231. if (pDeviceContext->DeviceType == NBT_DEVICE_REGULAR)
  9232. {
  9233. NbtUpBootCounter();
  9234. #ifdef REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
  9235. NbtNotifyTdiClients (pDeviceContext, NBT_TDI_DEREGISTER);
  9236. #else
  9237. NbtQueueTdiNotification (pDeviceContext, NBT_TDI_DEREGISTER);
  9238. #endif // REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
  9239. NbtDownBootCounter();
  9240. }
  9241. #endif
  9242. //
  9243. // Resync the cache since we may need to reset the outgoing interface info
  9244. //
  9245. StartTimer (NbtAddressChangeResyncCacheTimeout, ADDRESS_CHANGE_RESYNC_CACHE_TIMEOUT,
  9246. NULL, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
  9247. }
  9248. status = STATUS_SUCCESS;
  9249. }
  9250. else
  9251. {
  9252. ASSERT((signed)(pDeviceContext->TotalLowerConnections) >= 0);
  9253. NbtTrace(NBT_TRACE_PNP, ("new %!ipaddr! for device %p %Z",
  9254. IpAddress, pDeviceContext, &pDeviceContext->BindName));
  9255. CloseAddressesWithTransport(pDeviceContext);
  9256. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  9257. DisableInboundConnections (pDeviceContext);
  9258. // these are passed into here in the reverse byte order
  9259. //
  9260. IpAddress = htonl(IpAddress);
  9261. SubnetMask = htonl(SubnetMask);
  9262. //
  9263. // must be a new IP address, so open up the connections.
  9264. //
  9265. // get the ip address and open the required address
  9266. // objects with the underlying transport provider
  9267. CTEAttachFsp(&Attached, REF_FSP_NEWADDR);
  9268. Count = CountUpperConnections(pDeviceContext);
  9269. Count += NbtConfig.MinFreeLowerConnections;
  9270. for (i=0; i<2; i++) // Retry once!
  9271. {
  9272. status = NbtCreateAddressObjects (IpAddress, SubnetMask, pDeviceContext);
  9273. if (NT_SUCCESS(status))
  9274. {
  9275. // Allocate and set up connections with the transport provider.
  9276. while ((NT_SUCCESS(status)) && (Count--))
  9277. {
  9278. status = NbtOpenAndAssocConnection(pDeviceContext, NULL, NULL, '4');
  9279. }
  9280. if (!NT_SUCCESS(status))
  9281. {
  9282. NbtLogEvent (EVENT_NBT_CREATE_CONNECTION, status, Count);
  9283. KdPrint(("Nbt.NbtNewDhcpAddress: NbtOpenAndAssocConnection Failed <%x>\n",status));
  9284. }
  9285. break;
  9286. }
  9287. //
  9288. // Log an event only if it is a retry
  9289. //
  9290. if (i > 0)
  9291. {
  9292. NbtLogEvent (EVENT_NBT_CREATE_ADDRESS, status, i);
  9293. }
  9294. KdPrint(("Nbt.NbtNewDhcpAddress[i]: NbtCreateAddressObjects Failed, status=<%x>\n",i,status));
  9295. KdPrint(("Nbt.NbtNewDhcpAddress: IpAddress: %x, SubnetMask: %x, pDeviceContext: %x\n",
  9296. IpAddress, SubnetMask, pDeviceContext));
  9297. }
  9298. CTEDetachFsp(Attached, REF_FSP_NEWADDR);
  9299. CTEExReleaseResource(&NbtConfig.Resource);
  9300. #ifdef VXD
  9301. //
  9302. // Add the "permanent" name to the local name table. This is the IP
  9303. // address of the node padded out to 16 bytes with zeros.
  9304. //
  9305. NbtAddPermanentName(pDeviceContext);
  9306. #else
  9307. NbtCheckSetNameAdapterInfo (pDeviceContext, IpAddress);
  9308. if (pDeviceContext->DeviceType == NBT_DEVICE_REGULAR)
  9309. {
  9310. //
  9311. // Register this Device for our clients
  9312. //
  9313. NbtUpBootCounter();
  9314. #ifdef REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
  9315. NbtNotifyTdiClients (pDeviceContext, NBT_TDI_REGISTER);
  9316. #else
  9317. NbtQueueTdiNotification (pDeviceContext, NBT_TDI_REGISTER);
  9318. #endif // REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
  9319. NbtDownBootCounter();
  9320. }
  9321. //
  9322. // Resync the cache since we may need to reset the outgoing interface info
  9323. //
  9324. StartTimer (NbtAddressChangeResyncCacheTimeout, ADDRESS_CHANGE_RESYNC_CACHE_TIMEOUT,
  9325. NULL, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
  9326. #endif // VXD
  9327. }
  9328. return(status);
  9329. }
  9330. //----------------------------------------------------------------------------
  9331. NTSTATUS
  9332. NbtDeleteLowerConn(
  9333. IN tLOWERCONNECTION *pLowerConn
  9334. )
  9335. /*++
  9336. Routine Description:
  9337. This Routine attempts to delete a lower connection by closing it with the
  9338. transport and dereferencing it.
  9339. Arguments:
  9340. Return Value:
  9341. NONE
  9342. --*/
  9343. {
  9344. NTSTATUS status;
  9345. CTELockHandle OldIrq;
  9346. tDEVICECONTEXT *pDeviceContext;
  9347. status = STATUS_SUCCESS;
  9348. if ((pLowerConn->Verify != NBT_VERIFY_LOWERCONN) ||
  9349. (pLowerConn->RefCount > 500))
  9350. {
  9351. ASSERT (0);
  9352. return status;
  9353. }
  9354. // remove the lower connection from the active queue and then delete it
  9355. //
  9356. pDeviceContext = pLowerConn->pDeviceContext;
  9357. CTESpinLock(pDeviceContext,OldIrq);
  9358. //
  9359. // The lower conn can get removed from the inactive list in OutOfRsrcKill (when we queue it on
  9360. // the OutofRsrc.ConnectionHead). Check the flag that indicates this connection was dequed then.
  9361. //
  9362. if (!pLowerConn->OutOfRsrcFlag)
  9363. {
  9364. RemoveEntryList(&pLowerConn->Linkage);
  9365. pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (PLIST_ENTRY)0x00009789;
  9366. //
  9367. // Setting this TRUE to prevent from running the OutOfRsrcKill again.
  9368. //
  9369. pLowerConn->bNoOutRsrcKill = TRUE;
  9370. }
  9371. CTESpinFree(pDeviceContext,OldIrq);
  9372. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, FALSE);
  9373. return(status);
  9374. }
  9375. //----------------------------------------------------------------------------
  9376. VOID
  9377. DelayedWipeOutLowerconn(
  9378. IN tDGRAM_SEND_TRACKING *pUnused1,
  9379. IN PVOID pClientContext,
  9380. IN PVOID Unused2,
  9381. IN tDEVICECONTEXT *Unused3
  9382. )
  9383. /*++
  9384. Routine Description:
  9385. This routine does all the file close etc. that we couldn't do at dpc level
  9386. and then frees the memory.
  9387. Arguments:
  9388. pLowerConn - the lower connection to be wiped out
  9389. Return Value:
  9390. NONE
  9391. --*/
  9392. {
  9393. tLOWERCONNECTION *pLowerConn = (tLOWERCONNECTION*) pClientContext;
  9394. ASSERT(pLowerConn->Verify == NBT_VERIFY_LOWERCONN); // Verify LowerConn structure
  9395. // dereference the fileobject ptr
  9396. NTDereferenceObject((PVOID *)pLowerConn->pFileObject);
  9397. // close the lower connection with the transport
  9398. IF_DBG(NBT_DEBUG_NAMESRV)
  9399. KdPrint(("Nbt.DelayedWipeOutLowerconn: Closing Handle %X -> %X\n",pLowerConn,pLowerConn->FileHandle));
  9400. NbtTdiCloseConnection(pLowerConn);
  9401. // Close the Address object too since outbound connections use unique
  9402. // addresses for each connection, whereas inbound connections all use
  9403. // the same address ( and we don't want to close that address ever ).
  9404. if (pLowerConn->pAddrFileObject)
  9405. {
  9406. // dereference the fileobject ptr
  9407. NTDereferenceObject((PVOID *)pLowerConn->pAddrFileObject);
  9408. NbtTdiCloseAddress(pLowerConn);
  9409. }
  9410. #ifndef VXD
  9411. // free the indicate buffer and the mdl that holds it
  9412. //
  9413. CTEMemFree(MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl));
  9414. IoFreeMdl(pLowerConn->pIndicateMdl);
  9415. #endif
  9416. pLowerConn->Verify += 10;
  9417. // now free the memory block tracking this connection
  9418. CTEMemFree((PVOID)pLowerConn);
  9419. }
  9420. //----------------------------------------------------------------------------
  9421. VOID
  9422. NbtDereferenceClient(
  9423. IN tCLIENTELE *pClientEle
  9424. )
  9425. /*++
  9426. Routine Description
  9427. This routine deletes a client element record (which points to a name
  9428. in the local hash table. If this is the last client element hooked to that
  9429. name then the name is deleted too - causing a name release to be sent out.
  9430. Arguments:
  9431. Return Values:
  9432. TDI_STATUS - status of the request
  9433. --*/
  9434. {
  9435. CTELockHandle OldIrq;
  9436. CTELockHandle OldIrq1;
  9437. tADDRESSELE *pAddress;
  9438. PIRP pIrp;
  9439. NTSTATUS status;
  9440. tNAMEADDR *pNameAddr;
  9441. tTIMERQENTRY *pTimer;
  9442. tDGRAM_SEND_TRACKING *pTracker;
  9443. COMPLETIONCLIENT pClientCompletion = NULL;
  9444. PVOID Context;
  9445. LIST_ENTRY *pClientEntry;
  9446. tDEVICECONTEXT *pDeviceContext;
  9447. tCLIENTELE *pClientEleTemp;
  9448. BOOLEAN fLastClientOnDevice = TRUE;
  9449. // lock the JointLock
  9450. // so we can delete the client knowing that no one has a spin lock
  9451. // pending on the client - basically use the Joint spin lock to
  9452. // coordinate access to the AddressHead - NbtConnectionList also locks
  9453. // the JointLock to scan the AddressHead list
  9454. //
  9455. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  9456. ASSERT(pClientEle->RefCount);
  9457. ASSERT ((pClientEle->Verify==NBT_VERIFY_CLIENT) || (pClientEle->Verify==NBT_VERIFY_CLIENT_DOWN));
  9458. if (--pClientEle->RefCount)
  9459. {
  9460. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9461. // return pending because we haven't been able to close the client
  9462. // completely yet
  9463. //
  9464. return;
  9465. }
  9466. //
  9467. // Unlink the Client in this routine after the reference count has
  9468. // gone to zero since the DgramRcv code may need to find the client in
  9469. // the Address client list when it is distributing a single received
  9470. // dgram to several clients.
  9471. //
  9472. pIrp = pClientEle->pIrp;
  9473. pDeviceContext = pClientEle->pDeviceContext;
  9474. pAddress = pClientEle->pAddress;
  9475. pNameAddr = pAddress->pNameAddr;
  9476. CTESpinLock(pAddress,OldIrq1); // Need to acquire AddressEle lock -- Bug#: 231853
  9477. RemoveEntryList(&pClientEle->Linkage);
  9478. //
  9479. // If there is no other client registered on this device, then
  9480. // clear the adapter mask, and mark the release mask
  9481. //
  9482. pClientEntry = &pAddress->ClientHead;
  9483. while ((pClientEntry = pClientEntry->Flink) != &pAddress->ClientHead)
  9484. {
  9485. pClientEleTemp = CONTAINING_RECORD (pClientEntry,tCLIENTELE,Linkage);
  9486. if (pClientEleTemp->pDeviceContext == pDeviceContext)
  9487. {
  9488. fLastClientOnDevice = FALSE;
  9489. break;
  9490. }
  9491. }
  9492. CTESpinFree(pAddress,OldIrq1);
  9493. if (pNameAddr)
  9494. {
  9495. //
  9496. // If there is any timer running on this Client's device,
  9497. // stop it now!
  9498. //
  9499. if ((pTimer = pNameAddr->pTimer) &&
  9500. (pTracker = pTimer->Context) &&
  9501. (pTracker->pDeviceContext == pDeviceContext))
  9502. {
  9503. pNameAddr->pTimer = NULL;
  9504. StopTimer(pTimer,&pClientCompletion,&Context);
  9505. }
  9506. if (fLastClientOnDevice)
  9507. {
  9508. if (IsDeviceNetbiosless(pDeviceContext))
  9509. {
  9510. pNameAddr->NameFlags &= ~NAME_REGISTERED_ON_SMBDEV;
  9511. }
  9512. else
  9513. {
  9514. pNameAddr->AdapterMask &= ~pDeviceContext->AdapterMask;
  9515. pNameAddr->ConflictMask &= ~pDeviceContext->AdapterMask; // in case there was a conflict
  9516. pNameAddr->ReleaseMask |= pDeviceContext->AdapterMask;
  9517. }
  9518. }
  9519. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9520. #ifdef _PNP_POWER_
  9521. //
  9522. // Remove this name from the Adapter's Wakeup Pattern list (if set)
  9523. //
  9524. if ((pNameAddr->Name[0] != '*') &&
  9525. (pNameAddr->Name[NETBIOS_NAME_SIZE-1] == SPECIAL_SERVER_SUFFIX))
  9526. {
  9527. pDeviceContext->NumServers--;
  9528. CheckSetWakeupPattern (pDeviceContext, pNameAddr->Name, FALSE);
  9529. }
  9530. #endif // _PNP_POWER_
  9531. }
  9532. else
  9533. {
  9534. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9535. }
  9536. if (pClientCompletion)
  9537. {
  9538. (*pClientCompletion)(Context, STATUS_TIMEOUT);
  9539. }
  9540. //
  9541. // The Connection Q Should be Empty otherwise we shouldn't get to this routine
  9542. //
  9543. ASSERT(IsListEmpty(&pClientEle->ConnectActive));
  9544. ASSERT(IsListEmpty(&pClientEle->ConnectHead));
  9545. ASSERT(IsListEmpty(&pClientEle->ListenHead));
  9546. ASSERT(IsListEmpty(&pClientEle->SndDgrams)); // the Datagram Q should also be empty
  9547. // check if there are more clients attached to the address, or can we
  9548. // delete the address too.
  9549. //
  9550. NBT_DEREFERENCE_ADDRESS (pAddress, REF_ADDR_NEW_CLIENT);
  9551. IF_DBG(NBT_DEBUG_NAMESRV)
  9552. KdPrint(("Nbt.NbtDereferenceClient: Delete Client Object %X\n",pClientEle));
  9553. //
  9554. // if their is a client irp, complete now. When the permanent name is
  9555. // released there is no client irp.
  9556. //
  9557. // CHANGED:
  9558. // Do not hold up the client's irp until the name has released on the
  9559. // net. It is simpler to just complete it now
  9560. //
  9561. if (pIrp)
  9562. {
  9563. // complete the client's close address irp
  9564. CTEIoComplete(pIrp,STATUS_SUCCESS,0);
  9565. }
  9566. //
  9567. // free the memory associated with the client element
  9568. //
  9569. pClientEle->Verify += 10;
  9570. CTEMemFree((PVOID)pClientEle);
  9571. return;
  9572. }
  9573. //----------------------------------------------------------------------------
  9574. NTSTATUS
  9575. NbtDereferenceAddress(
  9576. IN tADDRESSELE *pAddress,
  9577. IN ULONG Context
  9578. )
  9579. /*++
  9580. Routine Description
  9581. This routine deletes an Address element record (which points to a name
  9582. in the local hash table). A name release is sent on the wire for this name.
  9583. Arguments:
  9584. Return Values:
  9585. TDI_STATUS - status of the request
  9586. --*/
  9587. {
  9588. NTSTATUS status;
  9589. CTELockHandle OldIrq;
  9590. CTELockHandle OldIrq1;
  9591. COMPLETIONCLIENT pClientCompletion = NULL;
  9592. PVOID pTimerContext;
  9593. ULONG SaveState;
  9594. tDEVICECONTEXT *pDeviceContext;
  9595. tTIMERQENTRY *pTimer;
  9596. // lock the hash table so another client cannot add a reference to this
  9597. // name before we delete it. We need the JointLock to keep the name
  9598. // refresh mechanism from finding the name in the list just as
  9599. // we are about to remove it (i.e. to synchronize with the name refresh
  9600. // code).
  9601. //
  9602. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  9603. CTESpinLock(pAddress,OldIrq);
  9604. ASSERT(pAddress->RefCount);
  9605. ASSERT (NBT_VERIFY_HANDLE (pAddress, NBT_VERIFY_ADDRESS));
  9606. if (pAddress->pNameAddr)
  9607. {
  9608. ASSERT (NBT_VERIFY_HANDLE (pAddress->pNameAddr, LOCAL_NAME));
  9609. }
  9610. if (--pAddress->RefCount)
  9611. {
  9612. CTESpinFree(pAddress,OldIrq);
  9613. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  9614. return(STATUS_SUCCESS);
  9615. }
  9616. //
  9617. // remove the address object from the list of addresses tied to the
  9618. // device context for the adapter
  9619. //
  9620. RemoveEntryList(&pAddress->Linkage);
  9621. ASSERT(IsListEmpty(&pAddress->ClientHead)); // The ClientHead should be empty
  9622. CTESpinFree(pAddress,OldIrq);
  9623. if (pAddress->pNameAddr)
  9624. {
  9625. IF_DBG(NBT_DEBUG_NAMESRV)
  9626. KdPrint(("Nbt.NbtDereferenceAddress: Freeing address object for <%-16.16s:%x>\n",
  9627. pAddress->pNameAddr->Name,pAddress->pNameAddr->Name[NETBIOS_NAME_SIZE-1] ));
  9628. pAddress->pNameAddr->pAddressEle = NULL;
  9629. //
  9630. // Release name on the network
  9631. // change the name state in the hash table since it is being released
  9632. //
  9633. SaveState = pAddress->pNameAddr->NameTypeState;
  9634. pAddress->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  9635. pAddress->pNameAddr->NameTypeState |= STATE_CONFLICT;
  9636. pAddress->pNameAddr->ReleaseMask |= pAddress->pNameAddr->AdapterMask;
  9637. pAddress->pNameAddr->AdapterMask = 0;
  9638. //
  9639. // check for any timers outstanding against the hash table entry - there shouldn't
  9640. // be any timers though
  9641. //
  9642. if (pTimer = pAddress->pNameAddr->pTimer)
  9643. {
  9644. pAddress->pNameAddr->pTimer = NULL;
  9645. status = StopTimer(pTimer, &pClientCompletion, &pTimerContext);
  9646. IF_DBG(NBT_DEBUG_NAMESRV)
  9647. KdPrint(("Nbt.NbtDereferenceAddress: StopTimer returned Context <%x>\n", pTimerContext));
  9648. if (pClientCompletion)
  9649. {
  9650. ASSERT (pClientCompletion != NameReleaseDone);
  9651. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  9652. (*pClientCompletion) (pTimerContext, STATUS_TIMEOUT);
  9653. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  9654. }
  9655. }
  9656. // only release the name on the net if it was not in conflict first
  9657. // This prevents name releases going out for names that were not actually
  9658. // claimed. Also, quick add names are not released on the net either.
  9659. //
  9660. if (!(SaveState & (STATE_CONFLICT | NAMETYPE_QUICK)) &&
  9661. (pAddress->pNameAddr->Name[0] != '*') &&
  9662. (pDeviceContext = GetAndRefNextDeviceFromNameAddr (pAddress->pNameAddr)))
  9663. {
  9664. //
  9665. // The pNameAddr has to stay around until the NameRelease has completed
  9666. //
  9667. NBT_REFERENCE_NAMEADDR (pAddress->pNameAddr, REF_NAME_RELEASE);
  9668. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  9669. status = ReleaseNameOnNet (pAddress->pNameAddr,
  9670. NbtConfig.pScope,
  9671. NameReleaseDone,
  9672. NodeType,
  9673. pDeviceContext);
  9674. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  9675. #ifndef VXD
  9676. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_GET_REF, TRUE);
  9677. #endif // !VXD
  9678. if (!NT_SUCCESS(status))
  9679. {
  9680. NBT_DEREFERENCE_NAMEADDR (pAddress->pNameAddr, REF_NAME_RELEASE, TRUE);
  9681. }
  9682. }
  9683. NBT_DEREFERENCE_NAMEADDR (pAddress->pNameAddr, REF_NAME_LOCAL, TRUE);
  9684. }
  9685. //
  9686. // Now, cleanup the Address info (we are still holding the JointLock)
  9687. //
  9688. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  9689. // free the memory associated with the address element
  9690. IF_DBG(NBT_DEBUG_NAMESRV)
  9691. KdPrint(("NBt: Deleteing Address Obj after name release on net %X\n",pAddress));
  9692. NbtFreeAddressObj(pAddress);
  9693. //
  9694. // the name has been deleted, so return success
  9695. //
  9696. return(STATUS_SUCCESS);
  9697. }
  9698. //----------------------------------------------------------------------------
  9699. VOID
  9700. NbtDereferenceName(
  9701. IN tNAMEADDR *pNameAddr,
  9702. IN ULONG RefContext,
  9703. IN BOOLEAN fLocked
  9704. )
  9705. /*++
  9706. Routine Description
  9707. This routine dereferences and possibly deletes a name element record by first unlinking from the
  9708. list it is in, and then freeing the memory if it is a local name. Remote
  9709. names remain in a circular list for reuse.
  9710. The JOINTLOCK may have been taken before calling this routine.
  9711. Arguments:
  9712. Return Values:
  9713. TDI_STATUS - status of the request
  9714. --*/
  9715. {
  9716. CTELockHandle OldIrq;
  9717. ULONG i;
  9718. if (!fLocked)
  9719. {
  9720. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  9721. }
  9722. ASSERT (NBT_VERIFY_HANDLE2 (pNameAddr, LOCAL_NAME, REMOTE_NAME));
  9723. ASSERT (pNameAddr->RefCount);
  9724. ASSERT (pNameAddr->References[RefContext]--);
  9725. if (--pNameAddr->RefCount)
  9726. {
  9727. if (!fLocked)
  9728. {
  9729. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9730. }
  9731. return;
  9732. }
  9733. IF_DBG(NBT_DEBUG_NAMESRV)
  9734. KdPrint(("Nbt.NbtDereferenceName[%s]: Freeing Name=<%16.16s:%x> %x\n",
  9735. (pNameAddr->Verify == REMOTE_NAME ? "Remote" : "Local"),
  9736. pNameAddr->Name, pNameAddr->Name[15], pNameAddr));
  9737. //
  9738. // remove from the hash table, could be set to NULL by DestroyHashTable
  9739. //
  9740. if (pNameAddr->Linkage.Flink && pNameAddr->Linkage.Blink) {
  9741. RemoveEntryList(&pNameAddr->Linkage);
  9742. } else {
  9743. // Both should be NULL
  9744. ASSERT(pNameAddr->Linkage.Flink == pNameAddr->Linkage.Blink);
  9745. }
  9746. if (pNameAddr->Verify == LOCAL_NAME)
  9747. {
  9748. ASSERT(!pNameAddr->pTimer);
  9749. ASSERT(NULL == pNameAddr->FQDN.Buffer);
  9750. ASSERT(0 == pNameAddr->FQDN.Length);
  9751. }
  9752. //
  9753. // if it is an internet group name it has a list of ip addresses and that
  9754. // memory block must be deleted
  9755. //
  9756. else if (pNameAddr->Verify == REMOTE_NAME)
  9757. {
  9758. NbtConfig.NumNameCached--;
  9759. //
  9760. // TBD: keep an exact number of the entries in the hash table.
  9761. //
  9762. // It can be negative since the pNameAddr may not be in hash table
  9763. // (It could be in the to-be-resolved list)
  9764. // for now, it is ok since exact number isn't critical.
  9765. //
  9766. if (NbtConfig.NumNameCached < 0) {
  9767. NbtConfig.NumNameCached = 0;
  9768. }
  9769. if (pNameAddr->NameAddFlags == (NAME_RESOLVED_BY_LMH_P | NAME_ADD_INET_GROUP))
  9770. {
  9771. if (pNameAddr->pLmhSvcGroupList)
  9772. {
  9773. IF_DBG(NBT_DEBUG_NAMESRV)
  9774. KdPrint(("Nbt.NbtDereferenceName: Freeing Pre-loaded Internet Group Name Memory = <%p>\n",
  9775. pNameAddr->pLmhSvcGroupList));
  9776. CTEMemFree((PVOID)pNameAddr->pLmhSvcGroupList);
  9777. }
  9778. }
  9779. if (pNameAddr->pRemoteIpAddrs)
  9780. {
  9781. for (i=0; i<pNameAddr->RemoteCacheLen; i++)
  9782. {
  9783. if (pNameAddr->pRemoteIpAddrs[i].pOrigIpAddrs)
  9784. {
  9785. IF_DBG(NBT_DEBUG_NAMESRV)
  9786. KdPrint(("Nbt.NbtDereferenceName: Freeing Internet Group Name Memory = <%p>\n",
  9787. pNameAddr->pRemoteIpAddrs[i].pOrigIpAddrs));
  9788. CTEMemFree((PVOID)pNameAddr->pRemoteIpAddrs[i].pOrigIpAddrs);
  9789. }
  9790. }
  9791. CTEMemFree ((PVOID)pNameAddr->pRemoteIpAddrs);
  9792. }
  9793. }
  9794. if (pNameAddr->pIpAddrsList)
  9795. {
  9796. CTEMemFree((PVOID)pNameAddr->pIpAddrsList);
  9797. }
  9798. if (NULL != pNameAddr->FQDN.Buffer) {
  9799. CTEMemFree((PVOID)pNameAddr->FQDN.Buffer);
  9800. pNameAddr->FQDN.Buffer = NULL;
  9801. pNameAddr->FQDN.Length = 0;
  9802. pNameAddr->FQDN.MaximumLength = 0;
  9803. }
  9804. //
  9805. // free the memory now
  9806. //
  9807. // #if DBG
  9808. pNameAddr->Verify += 10;
  9809. // #endif // DBG
  9810. CTEMemFree((PVOID)pNameAddr);
  9811. if (!fLocked)
  9812. {
  9813. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9814. }
  9815. }
  9816. //----------------------------------------------------------------------------
  9817. VOID
  9818. NbtDereferenceConnection(
  9819. IN tCONNECTELE *pConnEle,
  9820. IN ULONG RefContext
  9821. )
  9822. /*++
  9823. Routine Description
  9824. This routine dereferences and possibly deletes a connection element record.
  9825. Arguments:
  9826. Return Values:
  9827. TDI_STATUS - status of the request
  9828. --*/
  9829. {
  9830. PCTE_IRP pIrp;
  9831. CTELockHandle OldIrq;
  9832. CTELockHandle OldIrq1;
  9833. tDEVICECONTEXT *pDeviceContext;
  9834. tLOWERCONNECTION *pLowerConn;
  9835. PLIST_ENTRY pEntry;
  9836. CHECK_PTR(pConnEle);
  9837. // grab the lock of the item that contains the one we are trying to
  9838. // dereference and possibly delete. This prevents anyone from incrementing
  9839. // the count in between decrementing it and checking it for zero and deleting
  9840. // it if it is zero.
  9841. CTESpinLock(pConnEle,OldIrq);
  9842. ASSERT (pConnEle->RefCount > 0) ; // Check for too many derefs
  9843. ASSERT ((pConnEle->Verify==NBT_VERIFY_CONNECTION) || (pConnEle->Verify==NBT_VERIFY_CONNECTION_DOWN));
  9844. ASSERT (pConnEle->References[RefContext]--);
  9845. if (--pConnEle->RefCount)
  9846. {
  9847. CTESpinFree(pConnEle,OldIrq);
  9848. return;
  9849. }
  9850. ASSERT ((pConnEle->state <= NBT_CONNECTING) || (pConnEle->state > NBT_DISCONNECTING));
  9851. IF_DBG(NBT_DEBUG_NAMESRV)
  9852. KdPrint(("Nbt.NbtDereferenceConnection: Delete Connection Object %X\n",pConnEle));
  9853. #ifndef VXD
  9854. IoFreeMdl(pConnEle->pNewMdl);
  9855. //
  9856. // Clear the context value in the Fileobject so that if this connection
  9857. // is used again (erroneously) it will not pass the VerifyHandle test
  9858. //
  9859. if (pIrp = pConnEle->pIrpClose) // the close irp should be held in here
  9860. {
  9861. NTClearFileObjectContext(pConnEle->pIrpClose);
  9862. }
  9863. #endif
  9864. pDeviceContext = pConnEle->pDeviceContext;
  9865. CTESpinFree(pConnEle,OldIrq);
  9866. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  9867. CTESpinLock(pDeviceContext,OldIrq1);
  9868. // For outbound connections the lower connection is deleted in hndlrs.c
  9869. // For inbound connections, the lower connection is put back on the free
  9870. // list in hndlrs.c and one from that list is deleted here. Therefore
  9871. // delete a lower connection in this list if the connection is inbound.
  9872. //
  9873. if ((pDeviceContext->NumFreeLowerConnections > NbtConfig.MinFreeLowerConnections) &&
  9874. (pDeviceContext->NumFreeLowerConnections > (pDeviceContext->TotalLowerConnections/2)))
  9875. {
  9876. // get a lower connection from the free list and close it with the
  9877. // transport.
  9878. //
  9879. pEntry = RemoveHeadList(&pConnEle->pDeviceContext->LowerConnFreeHead);
  9880. pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
  9881. InterlockedDecrement (&pDeviceContext->NumFreeLowerConnections);
  9882. // close the lower connection with the transport
  9883. IF_DBG(NBT_DEBUG_NAMESRV)
  9884. KdPrint(("Nbt.NbtDereferenceConnection: Closing LowerConn %X -> %X\n",
  9885. pLowerConn,pLowerConn->FileHandle));
  9886. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, TRUE);
  9887. }
  9888. CTESpinFree(pDeviceContext,OldIrq1);
  9889. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9890. FreeConnectionObj(pConnEle); // free the memory block associated with the conn element
  9891. //
  9892. // The client may have sent down a close before NBT was done with the
  9893. // pConnEle, so Pending was returned and the irp stored in the pCOnnEle
  9894. // structure. Now that the structure is fully dereferenced, we can complete the irp.
  9895. //
  9896. if (pIrp)
  9897. {
  9898. CTEIoComplete(pIrp,STATUS_SUCCESS,0);
  9899. }
  9900. return;
  9901. }
  9902. //----------------------------------------------------------------------------
  9903. VOID
  9904. NbtDereferenceLowerConnection(
  9905. IN tLOWERCONNECTION *pLowerConn,
  9906. IN ULONG RefContext,
  9907. IN BOOLEAN fJointLockHeld
  9908. )
  9909. /*++
  9910. Routine Description:
  9911. This Routine decrements the reference count on a Lower Connection element and
  9912. if the value is zero, deletes the connection.
  9913. Arguments:
  9914. Return Value:
  9915. NONE
  9916. --*/
  9917. {
  9918. CTELockHandle OldIrq1;
  9919. tCONNECTELE *pConnEle;
  9920. NTSTATUS status;
  9921. CTESpinLock(pLowerConn,OldIrq1);
  9922. ASSERT (pLowerConn->Verify == NBT_VERIFY_LOWERCONN); // Verify LowerConn structure
  9923. ASSERT (pLowerConn->References[RefContext]--);
  9924. if(--pLowerConn->RefCount)
  9925. {
  9926. CTESpinFree(pLowerConn,OldIrq1);
  9927. return;
  9928. }
  9929. InterlockedDecrement (&pLowerConn->pDeviceContext->TotalLowerConnections);
  9930. IF_DBG(NBT_DEBUG_NAMESRV)
  9931. KdPrint(("Nbt.NbtDereferenceLowerConnection: Delete Lower Connection Object %p\n",pLowerConn));
  9932. //
  9933. // it's possible that transport may indicate before we run the code
  9934. // in DelayedWipeOutLowerconn. If that happens, we don't want to run this
  9935. // code again ( which will queue this to worker thread again!)
  9936. // So, bump it up to some large value
  9937. //
  9938. pLowerConn->RefCount = 1000;
  9939. if (NBT_VERIFY_HANDLE2((pConnEle = pLowerConn->pUpperConnection), NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
  9940. {
  9941. //
  9942. // We still have a linked UpperConnection block, so unlink it,
  9943. //
  9944. SET_STATE_UPPER (pLowerConn->pUpperConnection, NBT_DISCONNECTED);
  9945. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  9946. }
  9947. CTESpinFree(pLowerConn,OldIrq1);
  9948. //
  9949. // let's come back and do this later since we may be at dpc now
  9950. //
  9951. NTQueueToWorkerThread(
  9952. &pLowerConn->WorkItemCleanUpAndWipeOut,
  9953. DelayedWipeOutLowerconn,
  9954. NULL,
  9955. pLowerConn,
  9956. NULL,
  9957. NULL,
  9958. fJointLockHeld
  9959. );
  9960. }
  9961. //----------------------------------------------------------------------------
  9962. VOID
  9963. NbtDereferenceTracker(
  9964. IN tDGRAM_SEND_TRACKING *pTracker,
  9965. IN BOOLEAN fLocked
  9966. )
  9967. /*++
  9968. Routine Description:
  9969. This routine cleans up a Tracker block and puts it back on the free
  9970. queue. The JointLock Spin lock should be held before calling this
  9971. routine to coordinate access to the tracker ref count.
  9972. Arguments:
  9973. Return Value:
  9974. NTSTATUS - success or not
  9975. --*/
  9976. {
  9977. CTELockHandle OldIrq;
  9978. if (!fLocked)
  9979. {
  9980. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  9981. }
  9982. if (--pTracker->RefCount == 0)
  9983. {
  9984. // the datagram header may have already been freed
  9985. //
  9986. FreeTracker(pTracker, RELINK_TRACKER);
  9987. }
  9988. if (!fLocked)
  9989. {
  9990. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  9991. }
  9992. }
  9993. BOOL
  9994. IsLocalAddress(
  9995. tIPADDRESS IpAddress
  9996. )
  9997. {
  9998. tDEVICECONTEXT *pDeviceContext = NULL;
  9999. ULONG IPInterfaceContext = 0xffff, Metric = 0;
  10000. ULONG LoopbackIPInterfaceContext = 0xffff;
  10001. CTELockHandle OldIrq = 0;
  10002. PIPFASTQUERY pFastQuery;
  10003. if (0 == IpAddress) {
  10004. return TRUE;
  10005. }
  10006. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  10007. if (IsListEmpty(&NbtConfig.DeviceContexts)) {
  10008. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  10009. return FALSE;
  10010. }
  10011. pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink, tDEVICECONTEXT, Linkage);
  10012. pFastQuery = pDeviceContext->pFastQuery;
  10013. NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE);
  10014. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  10015. /*
  10016. * Hack!!!
  10017. */
  10018. if (NbtConfig.LoopbackIfContext == 0xffff) {
  10019. (pFastQuery)(htonl(INADDR_LOOPBACK), &LoopbackIPInterfaceContext, &Metric);
  10020. if (LoopbackIPInterfaceContext != 0xffff) {
  10021. NbtConfig.LoopbackIfContext = LoopbackIPInterfaceContext;
  10022. }
  10023. }
  10024. (pFastQuery)(htonl(IpAddress), &IPInterfaceContext, &Metric);
  10025. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, FALSE);
  10026. if (NbtConfig.LoopbackIfContext == 0xffff || IPInterfaceContext == 0xffff) {
  10027. return FALSE;
  10028. }
  10029. return (IPInterfaceContext == NbtConfig.LoopbackIfContext);
  10030. }
  10031. BOOL
  10032. IsSmbBoundToOutgoingInterface(
  10033. IN tIPADDRESS IpAddress
  10034. )
  10035. /*++
  10036. Routine Description:
  10037. This routine returns TRUE if the destionation can be reached through
  10038. an interface to which the SmbDevice is bound. Otherwise it returns FALSE
  10039. Arguments:
  10040. IpAddress The address of destination
  10041. Return Value:
  10042. TRUE/FALSE
  10043. --*/
  10044. {
  10045. tDEVICECONTEXT *pDeviceContext;
  10046. BOOL bBind;
  10047. if (IpAddress == INADDR_LOOPBACK) {
  10048. return TRUE;
  10049. }
  10050. /*
  10051. * First check if this is a local address
  10052. * return TRUE if it is a local address
  10053. */
  10054. if (IsLocalAddress(IpAddress)) {
  10055. return TRUE;
  10056. }
  10057. /*
  10058. * This is not a local IP. Check with TCP
  10059. */
  10060. pDeviceContext = GetDeviceFromInterface (htonl(IpAddress), TRUE);
  10061. bBind = (pDeviceContext && (pDeviceContext->AdapterMask & NbtConfig.ClientMask));
  10062. if (pDeviceContext) {
  10063. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_OUT_FROM_IP, FALSE);
  10064. }
  10065. return bBind;
  10066. }
  10067. // ========================================================================
  10068. // End of file.