Source code of Windows XP (NT5)
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.

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