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.

2468 lines
70 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Nbtutils.c
  5. Abstract:
  6. This file continas a number of utility and support routines for
  7. the NBT code.
  8. Author:
  9. Jim Stewart (Jimst) 10-2-92
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. // For some reason inclusion of dnsapi.h seems to cause build error
  14. //#include "dns.h" // for DNS_MAX_NAME_LENGTH
  15. //#include "windns.h" // for DNS_MAX_NAME_LENGTH
  16. #define DNS_MAX_NAME_LENGTH (255)
  17. //#if DBG
  18. LIST_ENTRY UsedIrps;
  19. //#endif
  20. NTSTATUS
  21. NewInternalAddressFromNetbios(
  22. IN PTA_NETBIOS_ADDRESS pTA,
  23. IN ULONG MaxInputBufferLength,
  24. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  25. );
  26. NTSTATUS
  27. NewInternalAddressFromNetbiosEX(
  28. IN PTA_NETBIOS_EX_ADDRESS pTA,
  29. IN ULONG MaxInputBufferLength,
  30. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  31. );
  32. NTSTATUS
  33. NewInternalAddressFromUnicodeAddress(
  34. IN PTA_NETBIOS_UNICODE_EX_ADDRESS pTA,
  35. IN ULONG MaxInputBufferLength,
  36. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  37. );
  38. //******************* Pageable Routine Declarations ****************
  39. #ifdef ALLOC_PRAGMA
  40. #pragma CTEMakePageable(PAGE, ConvertDottedDecimalToUlong)
  41. #pragma CTEMakePageable(PAGE, CloseLowerConnections)
  42. #endif
  43. //******************* Pageable Routine Declarations ****************
  44. //----------------------------------------------------------------------------
  45. BOOLEAN
  46. IsEntryInList(
  47. PLIST_ENTRY pEntryToFind,
  48. PLIST_ENTRY pListToSearch
  49. )
  50. {
  51. PLIST_ENTRY pEntry, pHead;
  52. pHead = pListToSearch;
  53. pEntry = pHead->Flink;
  54. while (pEntry != pHead)
  55. {
  56. if (pEntry == pEntryToFind)
  57. {
  58. //
  59. // This Entry is still valid
  60. //
  61. return (TRUE);
  62. }
  63. //
  64. // Go to next Entry
  65. //
  66. pEntry = pEntry->Flink;
  67. }
  68. return (FALSE);
  69. }
  70. //----------------------------------------------------------------------------
  71. void
  72. NbtFreeAddressObj(
  73. tADDRESSELE *pAddress
  74. )
  75. /*++
  76. Routine Description:
  77. This routine releases all memory associated with an Address object.
  78. Arguments:
  79. Return Value:
  80. none
  81. --*/
  82. {
  83. //
  84. // let's come back and do this later when it's not dpc time
  85. //
  86. CTEQueueForNonDispProcessing( DelayedFreeAddrObj,
  87. NULL,
  88. pAddress,
  89. NULL,
  90. NULL,
  91. FALSE);
  92. }
  93. //----------------------------------------------------------------------------
  94. VOID
  95. DelayedFreeAddrObj(
  96. IN tDGRAM_SEND_TRACKING *pUnused1,
  97. IN PVOID pClientContext,
  98. IN PVOID pUnused2,
  99. IN tDEVICECONTEXT *pUnused3
  100. )
  101. /*++
  102. Routine Description:
  103. This routine releases all memory associated with an Address object.
  104. Arguments:
  105. Return Value:
  106. none
  107. --*/
  108. {
  109. tADDRESSELE *pAddress = (tADDRESSELE *) pClientContext;
  110. ULONG SavedVerify = pAddress->Verify;
  111. #ifndef VXD
  112. if (pAddress->SecurityDescriptor)
  113. {
  114. SeDeassignSecurity(&pAddress->SecurityDescriptor);
  115. }
  116. #endif
  117. #if DBG
  118. CTEMemSet (pAddress, 0x12, sizeof(tADDRESSELE));
  119. #endif // DBG
  120. // free the address block itself
  121. // Modify the verify value so that another user of the same memory
  122. // block cannot accidently pass in a valid verifier
  123. pAddress->Verify = SavedVerify + 10;
  124. CTEMemFree ((PVOID) pAddress);
  125. }
  126. //----------------------------------------------------------------------------
  127. void
  128. NbtFreeClientObj(
  129. tCLIENTELE *pClientEle
  130. )
  131. /*++
  132. Routine Description:
  133. This routine releases all memory associated with Client object.
  134. Arguments:
  135. Return Value:
  136. none
  137. --*/
  138. {
  139. ULONG SavedVerify = pClientEle->Verify;
  140. #if DBG
  141. CTEMemSet (pClientEle, 0x12, sizeof(tCLIENTELE));
  142. #endif // DBG
  143. // Modify the verify value so that another user of the same memory
  144. // block cannot accidently pass in a valid verifier
  145. pClientEle->Verify = SavedVerify + 10;
  146. CTEMemFree ((PVOID) pClientEle);
  147. }
  148. //----------------------------------------------------------------------------
  149. void
  150. FreeConnectionObj(
  151. tCONNECTELE *pConnEle
  152. )
  153. /*++
  154. Routine Description:
  155. This routine releases all memory associated with a Connection object
  156. and then it frees the connection object itself.
  157. Arguments:
  158. Return Value:
  159. none
  160. --*/
  161. {
  162. ULONG SavedVerify = pConnEle->Verify;
  163. #if DBG
  164. CTEMemSet (pConnEle, 0x12, sizeof(tCONNECTELE));
  165. #endif // DBG
  166. // Modify the verify value so that another user of the same memory
  167. // block cannot accidently pass in a valid verifier
  168. pConnEle->Verify = SavedVerify + 10;
  169. CTEMemFree ((PVOID) pConnEle);
  170. }
  171. //----------------------------------------------------------------------------
  172. tCLIENTELE *
  173. NbtAllocateClientBlock(
  174. tADDRESSELE *pAddrEle,
  175. tDEVICECONTEXT *pDeviceContext
  176. )
  177. /*++
  178. Routine Description:
  179. This routine allocates a block of memory for a client openning an
  180. address. It fills in default values for the block and links the
  181. block to the addresslist. The AddressEle spin lock is held when this
  182. routine is called.
  183. Arguments:
  184. Return Value:
  185. none
  186. --*/
  187. {
  188. tCLIENTELE *pClientElement;
  189. // allocate memory for the client block
  190. pClientElement = (tCLIENTELE *) NbtAllocMem (sizeof (tCLIENTELE), NBT_TAG2('05'));
  191. if (!pClientElement)
  192. {
  193. ASSERTMSG("Unable to allocate Memory for a client block\n",
  194. pClientElement);
  195. return(NULL);
  196. }
  197. CTEZeroMemory((PVOID)pClientElement,sizeof(tCLIENTELE));
  198. CTEInitLock(&pClientElement->LockInfo.SpinLock);
  199. #if DBG
  200. pClientElement->LockInfo.LockNumber = CLIENT_LOCK;
  201. #endif
  202. // Set Event handler function pointers to default routines provided by
  203. // TDI
  204. #ifndef VXD
  205. pClientElement->evConnect = TdiDefaultConnectHandler;
  206. pClientElement->evReceive = TdiDefaultReceiveHandler;
  207. pClientElement->evDisconnect = TdiDefaultDisconnectHandler;
  208. pClientElement->evError = TdiDefaultErrorHandler;
  209. pClientElement->evRcvDgram = TdiDefaultRcvDatagramHandler;
  210. pClientElement->evRcvExpedited = TdiDefaultRcvExpeditedHandler;
  211. pClientElement->evSendPossible = TdiDefaultSendPossibleHandler;
  212. #else
  213. //
  214. // VXD provides no client support for event handlers but does
  215. // make use of some of the event handlers itself (for RcvAny processing
  216. // and disconnect cleanup).
  217. //
  218. pClientElement->evConnect = NULL ;
  219. pClientElement->evReceive = NULL ;
  220. pClientElement->RcvEvContext = NULL ;
  221. pClientElement->evDisconnect = NULL ;
  222. pClientElement->evError = NULL ;
  223. pClientElement->evRcvDgram = NULL ;
  224. pClientElement->evRcvExpedited = NULL ;
  225. pClientElement->evSendPossible = NULL ;
  226. #endif
  227. pClientElement->RefCount = 1;
  228. // there are no rcvs or snds yet
  229. InitializeListHead(&pClientElement->RcvDgramHead);
  230. InitializeListHead(&pClientElement->ListenHead);
  231. InitializeListHead(&pClientElement->SndDgrams);
  232. InitializeListHead(&pClientElement->ConnectActive);
  233. InitializeListHead(&pClientElement->ConnectHead);
  234. #ifdef VXD
  235. InitializeListHead(&pClientElement->RcvAnyHead);
  236. pClientElement->fDeregistered = FALSE ;
  237. #endif
  238. pClientElement->pIrp = NULL;
  239. // copy a special value into the verify long so that we can verify
  240. // connection ptrs passed back from the application
  241. pClientElement->Verify = NBT_VERIFY_CLIENT;
  242. pClientElement->pAddress = (PVOID)pAddrEle; // link the client block to the Address element.
  243. pClientElement->pDeviceContext = pDeviceContext; // adapter this name is registered against.
  244. // put the new Client element block on the end of the linked list tied to
  245. // the address element
  246. InsertTailList(&pAddrEle->ClientHead,&pClientElement->Linkage);
  247. return(pClientElement);
  248. }
  249. //----------------------------------------------------------------------------
  250. NTSTATUS
  251. NbtAddPermanentName(
  252. IN tDEVICECONTEXT *pDeviceContext
  253. )
  254. /*++
  255. Routine Description:
  256. This routine adds the node permanent name to the local name table. This
  257. is the node's MAC address padded out to 16 bytes with zeros.
  258. Arguments:
  259. DeviceContext - Adapter to add permanent
  260. pIrp - Irp (optional) to complete after name has been added
  261. Return Value:
  262. status
  263. --*/
  264. {
  265. NTSTATUS status;
  266. TDI_REQUEST Request;
  267. TA_NETBIOS_ADDRESS Address;
  268. UCHAR pName[NETBIOS_NAME_SIZE];
  269. USHORT uType;
  270. CTELockHandle OldIrq, OldIrq1;
  271. tNAMEADDR *pNameAddr;
  272. tCLIENTELE *pClientEle;
  273. CTEZeroMemory(pName,NETBIOS_NAME_SIZE);
  274. CTEMemCopy(&pName[10],&pDeviceContext->MacAddress.Address[0],sizeof(tMAC_ADDRESS));
  275. //
  276. // be sure the name has not already been added
  277. //
  278. if (pDeviceContext->pPermClient)
  279. {
  280. if (CTEMemEqu(pDeviceContext->pPermClient->pAddress->pNameAddr->Name, pName, NETBIOS_NAME_SIZE))
  281. {
  282. return(STATUS_SUCCESS);
  283. }
  284. else
  285. {
  286. NbtRemovePermanentName(pDeviceContext);
  287. }
  288. }
  289. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  290. //
  291. // check if the name is already in the hash table
  292. //
  293. status = FindInHashTable (pNbtGlobConfig->pLocalHashTbl, pName, NbtConfig.pScope, &pNameAddr);
  294. if ((NT_SUCCESS(status)) && (pNameAddr->pAddressEle))
  295. {
  296. //
  297. // Acquire Address Spinlock since we may be accessing the ClientHead list
  298. // Bug #: 230820
  299. //
  300. CTESpinLock(pNameAddr->pAddressEle,OldIrq1);
  301. //
  302. // create client block and link to addresslist
  303. // pass back the client block address as a handle for future reference
  304. // to the client
  305. //
  306. pClientEle = NbtAllocateClientBlock (pNameAddr->pAddressEle, pDeviceContext);
  307. if (!pClientEle)
  308. {
  309. CTESpinFree(pNameAddr->pAddressEle,OldIrq1);
  310. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  311. return(STATUS_INSUFFICIENT_RESOURCES);
  312. }
  313. NBT_REFERENCE_ADDRESS (pNameAddr->pAddressEle, REF_ADDR_NEW_CLIENT);
  314. CTESpinFree(pNameAddr->pAddressEle,OldIrq1);
  315. //
  316. // reset the ip address incase the the address got set to loop back
  317. // by a client releasing and re-openning the permanent name while there
  318. // was no ip address for this node.
  319. //
  320. pNameAddr->IpAddress = pDeviceContext->IpAddress;
  321. // turn on the adapter's bit in the adapter Mask and set the
  322. // re-register flag so we register the name out the new adapter.
  323. //
  324. pNameAddr->AdapterMask |= pDeviceContext->AdapterMask;
  325. pNameAddr->NameTypeState |= NAMETYPE_QUICK;
  326. IF_DBG(NBT_DEBUG_NAMESRV)
  327. KdPrint(("Nbt: Adding Permanent name %15.15s<%X> \n", pName,(UCHAR)pName[15]));
  328. }
  329. else
  330. {
  331. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  332. // make up the Request data structure from the IRP info
  333. Request.Handle.AddressHandle = NULL;
  334. //
  335. // Make it a Quick name so it does not get registered on the net
  336. //
  337. Address.TAAddressCount = 1;
  338. Address.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  339. Address.Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
  340. Address.Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
  341. CTEMemCopy(Address.Address[0].Address[0].NetbiosName,pName,NETBIOS_NAME_SIZE);
  342. status = NbtOpenAddress(&Request,
  343. (PTA_ADDRESS)&Address.Address[0],
  344. pDeviceContext->IpAddress,
  345. NULL,
  346. pDeviceContext,
  347. NULL);
  348. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  349. pClientEle = (tCLIENTELE *)Request.Handle.AddressHandle;
  350. }
  351. //
  352. // save the client element so we can remove the permanent name later
  353. // if required
  354. //
  355. if (NT_SUCCESS(status))
  356. {
  357. pDeviceContext->pPermClient = pClientEle;
  358. #ifdef VXD
  359. //
  360. // 0th element is for perm. name: store it.
  361. //
  362. pDeviceContext->pNameTable[0] = pClientEle;
  363. #endif
  364. }
  365. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  366. return(status);
  367. }
  368. //----------------------------------------------------------------------------
  369. VOID
  370. NbtRemovePermanentName(
  371. IN tDEVICECONTEXT *pDeviceContext
  372. )
  373. /*++
  374. Routine Description:
  375. This routine remomves the node permanent name to the local name table.
  376. Arguments:
  377. DeviceContext - Adapter to add permanent
  378. pIrp - Irp (optional) to complete after name has been added
  379. Return Value:
  380. status
  381. --*/
  382. {
  383. NTSTATUS status;
  384. tNAMEADDR *pNameAddr;
  385. CTELockHandle OldIrq;
  386. tCLIENTELE *pClientEle;
  387. tADDRESSELE *pAddressEle;
  388. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  389. if (pDeviceContext->pPermClient)
  390. {
  391. //
  392. // We need to free the client and set the perm name ptr to null
  393. //
  394. pClientEle = pDeviceContext->pPermClient;
  395. pDeviceContext->pPermClient = NULL;
  396. #ifdef VXD
  397. pDeviceContext->pNameTable[0] = NULL;
  398. #endif
  399. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  400. NBT_DEREFERENCE_CLIENT(pClientEle);
  401. }
  402. else
  403. {
  404. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  405. }
  406. }
  407. //----------------------------------------------------------------------------
  408. NTSTATUS
  409. ConvertDottedDecimalToUlong(
  410. IN PUCHAR pInString,
  411. OUT PULONG IpAddress
  412. )
  413. /*++
  414. Routine Description:
  415. This routine converts a unicode dotted decimal IP address into
  416. a 4 element array with each element being USHORT.
  417. Arguments:
  418. Return Value:
  419. NTSTATUS
  420. --*/
  421. {
  422. USHORT i;
  423. ULONG value;
  424. int iSum =0;
  425. ULONG k = 0;
  426. UCHAR Chr;
  427. UCHAR pArray[4];
  428. CTEPagedCode();
  429. pArray[0] = 0;
  430. // go through each character in the string, skipping "periods", converting
  431. // to integer by subtracting the value of '0'
  432. //
  433. while ((Chr = *pInString++) && (Chr != ' ') )
  434. {
  435. if (Chr == '.')
  436. {
  437. // be sure not to overflow a byte.
  438. if (iSum <= 0xFF)
  439. pArray[k] = (UCHAR) iSum;
  440. else
  441. return(STATUS_UNSUCCESSFUL);
  442. // check for too many periods in the address
  443. if (++k > 3)
  444. return STATUS_UNSUCCESSFUL;
  445. pArray[k] = 0;
  446. iSum = 0;
  447. }
  448. else
  449. {
  450. Chr = Chr - '0';
  451. // be sure character is a number 0..9
  452. if ((Chr < 0) || (Chr > 9))
  453. return(STATUS_UNSUCCESSFUL);
  454. iSum = iSum*10 + Chr;
  455. }
  456. }
  457. // save the last sum in the byte and be sure there are 4 pieces to the
  458. // address
  459. if ((iSum <= 0xFF) && (k == 3))
  460. pArray[k] = (UCHAR) iSum;
  461. else
  462. return(STATUS_UNSUCCESSFUL);
  463. // now convert to a ULONG, in network order...
  464. value = 0;
  465. // go through the array of bytes and concatenate into a ULONG
  466. for (i=0; i < 4; i++ )
  467. {
  468. value = (value << 8) + pArray[i];
  469. }
  470. *IpAddress = value;
  471. return(STATUS_SUCCESS);
  472. }
  473. //----------------------------------------------------------------------------
  474. NTSTATUS
  475. NbtInitQ(
  476. PLIST_ENTRY pListHead,
  477. LONG iSizeBuffer,
  478. LONG iNumBuffers
  479. )
  480. /*++
  481. Routine Description:
  482. This routine allocates memory blocks for doubly linked lists and links
  483. them to a list.
  484. Arguments:
  485. ppListHead - a ptr to a ptr to the list head to add buffer to
  486. iSizeBuffer - size of the buffer to add to the list head
  487. iNumBuffers - the number of buffers to add to the queue
  488. Return Value:
  489. none
  490. --*/
  491. {
  492. int i;
  493. PLIST_ENTRY pBuffer;
  494. // NOTE THAT THIS ASSUMES THAT THE LINKAGE PTRS FOR EACH BLOCK ARE AT
  495. // THE START OF THE BLOCK - so it will not work correctly if
  496. // the various types in types.h change to move "Linkage" to a position
  497. // other than at the start of each structure to be chained
  498. for (i=0;i<iNumBuffers ;i++ )
  499. {
  500. pBuffer =(PLIST_ENTRY) NbtAllocMem (iSizeBuffer, NBT_TAG2('06'));
  501. if (!pBuffer)
  502. {
  503. return(STATUS_INSUFFICIENT_RESOURCES);
  504. }
  505. else
  506. {
  507. InsertHeadList(pListHead,pBuffer);
  508. }
  509. }
  510. return(STATUS_SUCCESS);
  511. }
  512. //----------------------------------------------------------------------------
  513. NTSTATUS
  514. NbtGetBuffer(
  515. PLIST_ENTRY pListHead,
  516. PLIST_ENTRY *ppListEntry,
  517. enum eBUFFER_TYPES eBuffType)
  518. /*++
  519. Routine Description:
  520. This routine tries to get a memory block and if it fails it allocates
  521. another set of buffers.
  522. Arguments:
  523. ppListHead - a ptr to a ptr to the list head to add buffer to
  524. iSizeBuffer - size of the buffer to add to the list head
  525. iNumBuffers - the number of buffers to add to the queue
  526. Return Value:
  527. none
  528. --*/
  529. {
  530. NTSTATUS status;
  531. if (IsListEmpty(pListHead))
  532. {
  533. // check if we are allowed to allocate more memory blocks
  534. if (NbtConfig.iCurrentNumBuff[eBuffType] >=
  535. pNbtGlobConfig->iMaxNumBuff[eBuffType] )
  536. {
  537. return(STATUS_INSUFFICIENT_RESOURCES);
  538. }
  539. // no memory blocks, so allocate another one
  540. status = NbtInitQ(
  541. pListHead,
  542. pNbtGlobConfig->iBufferSize[eBuffType],
  543. 1);
  544. if (!NT_SUCCESS(status))
  545. {
  546. return(status);
  547. }
  548. NbtConfig.iCurrentNumBuff[eBuffType]++;
  549. *ppListEntry = RemoveHeadList(pListHead);
  550. }
  551. else
  552. {
  553. *ppListEntry = RemoveHeadList(pListHead);
  554. }
  555. return(STATUS_SUCCESS);
  556. }
  557. NTSTATUS
  558. NetbiosAddressToInternalAddress(
  559. IN PTA_NETBIOS_ADDRESS pTA,
  560. IN ULONG MaxInputBufferLength,
  561. OUT PTDI_ADDRESS_NETBT_INTERNAL pNetBT
  562. )
  563. {
  564. //
  565. // name could be longer than 16 bytes (dns name), but make sure it's at
  566. // least 16 bytes (sizeof(TDI_ADDRESS_NETBIOS) == (16 + sizeof(USHORT)))
  567. //
  568. if (pTA->Address[0].AddressLength < sizeof(TDI_ADDRESS_NETBIOS)) {
  569. return(STATUS_INVALID_PARAMETER);
  570. }
  571. pNetBT->NameType = pTA->Address[0].Address[0].NetbiosNameType;
  572. pNetBT->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  573. pNetBT->OEMEndpointName.Buffer = NULL;
  574. pNetBT->OEMEndpointName.Length = pNetBT->OEMEndpointName.MaximumLength = 0;
  575. /* Here we bent OEM_STRING a little bit, we allow Length == MaximumLength */
  576. /* That is, Rtl routines cannot be used since they expect null-terminated Buffer */
  577. pNetBT->OEMRemoteName.MaximumLength = pNetBT->OEMRemoteName.Length =
  578. pTA->Address[0].AddressLength - (sizeof(TDI_ADDRESS_NETBIOS) - NETBIOS_NAME_SIZE);
  579. pNetBT->OEMRemoteName.Buffer = pTA->Address[0].Address[0].NetbiosName;
  580. pNetBT->pNetbiosUnicodeEX = NULL;
  581. return STATUS_SUCCESS;
  582. }
  583. NTSTATUS
  584. NetbiosEXAddressToInternalAddress(
  585. IN PTA_NETBIOS_EX_ADDRESS pTA,
  586. IN ULONG MaxInputBufferLength,
  587. OUT PTDI_ADDRESS_NETBT_INTERNAL pNetBT
  588. )
  589. {
  590. //
  591. // Check for the minimum acceptable length for this type of address
  592. //
  593. if (MaxInputBufferLength < sizeof (TA_NETBIOS_EX_ADDRESS)) {
  594. ASSERT (0);
  595. return (STATUS_INVALID_ADDRESS);
  596. }
  597. pNetBT->OEMEndpointName.Buffer = pTA->Address[0].Address[0].EndpointName;
  598. pNetBT->OEMEndpointName.Length = pNetBT->OEMEndpointName.MaximumLength = NETBIOS_NAME_SIZE;
  599. pNetBT->NameType = pTA->Address[0].Address[0].NetbiosAddress.NetbiosNameType;
  600. pNetBT->AddressType = TDI_ADDRESS_TYPE_NETBIOS_EX;
  601. pNetBT->OEMRemoteName.MaximumLength = pNetBT->OEMRemoteName.Length =
  602. pTA->Address[0].AddressLength -
  603. FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) -
  604. FIELD_OFFSET(TDI_ADDRESS_NETBIOS,NetbiosName);
  605. pNetBT->OEMRemoteName.Buffer = pTA->Address[0].Address[0].NetbiosAddress.NetbiosName;
  606. pNetBT->pNetbiosUnicodeEX = NULL;
  607. return STATUS_SUCCESS;
  608. }
  609. NTSTATUS
  610. NewInternalAddressFromNetbiosEX(
  611. IN PTA_NETBIOS_EX_ADDRESS pTA,
  612. IN ULONG MaxInputBufferLength,
  613. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  614. )
  615. {
  616. ULONG required_size;
  617. PTA_NETBT_INTERNAL_ADDRESS p;
  618. PTDI_ADDRESS_NETBT_INTERNAL pNetBT;
  619. TDI_ADDRESS_NETBT_INTERNAL ta;
  620. ppNetBT[0] = NULL;
  621. if (!NT_SUCCESS(NetbiosEXAddressToInternalAddress(pTA, MaxInputBufferLength, &ta))) {
  622. return (STATUS_INVALID_ADDRESS);
  623. }
  624. required_size = NBT_DWORD_ALIGN(sizeof(TA_NETBT_INTERNAL_ADDRESS)) +
  625. NBT_DWORD_ALIGN(ta.OEMRemoteName.Length+1) +
  626. NBT_DWORD_ALIGN(ta.OEMEndpointName.Length+1);
  627. p = (PTA_NETBT_INTERNAL_ADDRESS)NbtAllocMem (required_size, NBT_TAG2('TA'));
  628. if (p == NULL) {
  629. return STATUS_INSUFFICIENT_RESOURCES;
  630. }
  631. CTEZeroMemory(p, required_size);
  632. // From now on, we cannot have failure.
  633. pNetBT = p->Address[0].Address;
  634. p->TAAddressCount = 1;
  635. p->Address[0].AddressLength = sizeof(TA_NETBT_INTERNAL_ADDRESS);
  636. p->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC;
  637. pNetBT->NameType = ta.NameType;
  638. pNetBT->AddressType = ta.AddressType;
  639. pNetBT->OEMRemoteName.MaximumLength = NBT_DWORD_ALIGN(ta.OEMRemoteName.Length+1);
  640. pNetBT->OEMRemoteName.Length = ta.OEMRemoteName.Length;
  641. pNetBT->OEMRemoteName.Buffer = (PVOID)((PUCHAR)p + NBT_DWORD_ALIGN(sizeof(TA_NETBT_INTERNAL_ADDRESS)));
  642. ASSERT((ta.OEMRemoteName.Length % sizeof(ta.OEMRemoteName.Buffer[0])) == 0);
  643. CTEMemCopy(pNetBT->OEMRemoteName.Buffer, ta.OEMRemoteName.Buffer, ta.OEMRemoteName.Length);
  644. pNetBT->OEMRemoteName.Buffer[ta.OEMRemoteName.Length/sizeof(ta.OEMRemoteName.Buffer[0])] = 0;
  645. pNetBT->OEMEndpointName.MaximumLength = NBT_DWORD_ALIGN(ta.OEMEndpointName.Length+1);
  646. pNetBT->OEMEndpointName.Length = ta.OEMEndpointName.Length;
  647. pNetBT->OEMEndpointName.Buffer = (PVOID)((PUCHAR)pNetBT->OEMRemoteName.Buffer +
  648. pNetBT->OEMRemoteName.MaximumLength);
  649. ASSERT((ta.OEMEndpointName.Length % sizeof(ta.OEMEndpointName.Buffer[0])) == 0);
  650. CTEMemCopy(pNetBT->OEMEndpointName.Buffer, ta.OEMEndpointName.Buffer, ta.OEMEndpointName.Length);
  651. pNetBT->OEMEndpointName.Buffer[ta.OEMEndpointName.Length/sizeof(ta.OEMEndpointName.Buffer[0])] = 0;
  652. pNetBT->pNetbiosUnicodeEX = NULL;
  653. ppNetBT[0] = p;
  654. return STATUS_SUCCESS;
  655. }
  656. NTSTATUS
  657. NewInternalAddressFromNetbios(
  658. IN PTA_NETBIOS_ADDRESS pTA,
  659. IN ULONG MaxInputBufferLength,
  660. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  661. )
  662. {
  663. ULONG required_size;
  664. PTA_NETBT_INTERNAL_ADDRESS p;
  665. PTDI_ADDRESS_NETBT_INTERNAL pNetBT;
  666. TDI_ADDRESS_NETBT_INTERNAL ta;
  667. ppNetBT[0] = NULL;
  668. if (!NT_SUCCESS(NetbiosAddressToInternalAddress(pTA, MaxInputBufferLength, &ta))) {
  669. return (STATUS_INVALID_ADDRESS);
  670. }
  671. required_size = NBT_DWORD_ALIGN(sizeof(TA_NETBT_INTERNAL_ADDRESS)) +
  672. NBT_DWORD_ALIGN(ta.OEMRemoteName.Length+1);
  673. p = (PTA_NETBT_INTERNAL_ADDRESS)NbtAllocMem (required_size, NBT_TAG2('TA'));
  674. if (p == NULL) {
  675. return STATUS_INSUFFICIENT_RESOURCES;
  676. }
  677. CTEZeroMemory(p, required_size);
  678. // From now on, we cannot have failure.
  679. pNetBT = p->Address[0].Address;
  680. p->TAAddressCount = 1;
  681. p->Address[0].AddressLength = sizeof(TA_NETBT_INTERNAL_ADDRESS);
  682. p->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC;
  683. pNetBT->NameType = ta.NameType;
  684. pNetBT->AddressType = ta.AddressType;
  685. pNetBT->OEMRemoteName.MaximumLength = NBT_DWORD_ALIGN(ta.OEMRemoteName.Length+1);
  686. pNetBT->OEMRemoteName.Length = ta.OEMRemoteName.Length;
  687. pNetBT->OEMRemoteName.Buffer = (PVOID)((PUCHAR)p + NBT_DWORD_ALIGN(sizeof(TA_NETBT_INTERNAL_ADDRESS)));
  688. ASSERT((ta.OEMRemoteName.Length % sizeof(ta.OEMRemoteName.Buffer[0])) == 0);
  689. CTEMemCopy(pNetBT->OEMRemoteName.Buffer, ta.OEMRemoteName.Buffer, ta.OEMRemoteName.Length);
  690. pNetBT->OEMRemoteName.Buffer[ta.OEMRemoteName.Length/sizeof(ta.OEMRemoteName.Buffer[0])] = 0;
  691. pNetBT->pNetbiosUnicodeEX = NULL;
  692. pNetBT->OEMEndpointName.MaximumLength = 0;
  693. pNetBT->OEMEndpointName.Length = 0;
  694. pNetBT->OEMEndpointName.Buffer = NULL;
  695. ppNetBT[0] = p;
  696. return STATUS_SUCCESS;
  697. }
  698. NTSTATUS
  699. NewInternalAddressFromUnicodeAddress(
  700. IN PTA_NETBIOS_UNICODE_EX_ADDRESS pTA,
  701. IN ULONG MaxInputBufferLength,
  702. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  703. )
  704. {
  705. OEM_STRING OemEndpoint, OemRemote;
  706. UNICODE_STRING temp;
  707. ULONG required_size;
  708. PTA_NETBT_INTERNAL_ADDRESS p;
  709. PTDI_ADDRESS_NETBT_INTERNAL pNetBT;
  710. int remote_len;
  711. ppNetBT[0] = NULL;
  712. if (MaxInputBufferLength < sizeof (TDI_ADDRESS_NETBIOS_UNICODE_EX)) {
  713. ASSERT (0);
  714. return (STATUS_INVALID_ADDRESS);
  715. }
  716. switch(pTA->Address[0].Address[0].NameBufferType) {
  717. case NBT_READONLY:
  718. case NBT_WRITEONLY:
  719. case NBT_READWRITE:
  720. case NBT_WRITTEN:
  721. break;
  722. default:
  723. ASSERT(FALSE);
  724. return (STATUS_INVALID_ADDRESS);
  725. }
  726. /* unaligned */
  727. CTEMemCopy(&temp, &pTA->Address[0].Address[0].RemoteName, sizeof(temp));
  728. if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemRemote, &temp, TRUE))) {
  729. return (STATUS_INVALID_ADDRESS);
  730. }
  731. CTEMemCopy(&temp, &pTA->Address[0].Address[0].EndpointName, sizeof(temp));
  732. if (!NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemEndpoint, &temp, TRUE))) {
  733. RtlFreeOemString(&OemRemote);
  734. return (STATUS_INVALID_ADDRESS);
  735. }
  736. /*
  737. * Other NetBT may never expect that remote_len and endpoint_len can be less than NETBIOS_NAME_SIZE.
  738. * Some of them may try to access 15th byte of the name.
  739. * In NETBIOS_NAME_TYPE and NETBIOS_EX_NAME_TYPE, at least NETBIOS_NAME_SIZE bytes are required for each name.
  740. */
  741. remote_len = OemRemote.MaximumLength;
  742. if (remote_len <= NETBIOS_NAME_SIZE) {
  743. remote_len = NETBIOS_NAME_SIZE + 1;
  744. }
  745. /* Calculate the needed buffer size */
  746. required_size = NBT_DWORD_ALIGN(sizeof(TA_NETBT_INTERNAL_ADDRESS)) +
  747. NBT_DWORD_ALIGN(remote_len) + // For OEM remote
  748. NBT_DWORD_ALIGN((NETBIOS_NAME_SIZE+1)*sizeof(OemEndpoint.Buffer[0]));
  749. p = (PTA_NETBT_INTERNAL_ADDRESS)NbtAllocMem (required_size, NBT_TAG2('TA'));
  750. if (p == NULL) {
  751. RtlFreeOemString(&OemRemote);
  752. RtlFreeOemString(&OemEndpoint);
  753. return STATUS_INSUFFICIENT_RESOURCES;
  754. }
  755. CTEZeroMemory(p, required_size);
  756. // From now on, we cannot have failure.
  757. pNetBT = p->Address[0].Address;
  758. p->TAAddressCount = 1;
  759. p->Address[0].AddressLength = sizeof(TA_NETBT_INTERNAL_ADDRESS);
  760. p->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC;
  761. pNetBT->NameType = pTA->Address[0].Address[0].NetbiosNameType;
  762. pNetBT->AddressType = TDI_ADDRESS_TYPE_NETBIOS_EX; // map to NETBIOS_EX
  763. // copy OEM EndpointName
  764. pNetBT->OEMEndpointName.Buffer =
  765. (PVOID)((PUCHAR)p + NBT_DWORD_ALIGN(sizeof(TA_NETBT_INTERNAL_ADDRESS)));
  766. pNetBT->OEMEndpointName.MaximumLength = NBT_DWORD_ALIGN((NETBIOS_NAME_SIZE+1));
  767. pNetBT->OEMEndpointName.Length = NETBIOS_NAME_SIZE;
  768. ASSERT((NETBIOS_NAME_SIZE % sizeof(OemRemote.Buffer[0])) == 0);
  769. if (OemEndpoint.Length < NETBIOS_NAME_SIZE) {
  770. memset(pNetBT->OEMEndpointName.Buffer + OemEndpoint.Length, ' ', NETBIOS_NAME_SIZE);
  771. CTEMemCopy(pNetBT->OEMEndpointName.Buffer, OemEndpoint.Buffer, OemEndpoint.Length);
  772. } else {
  773. CTEMemCopy(pNetBT->OEMEndpointName.Buffer, OemEndpoint.Buffer, NETBIOS_NAME_SIZE);
  774. }
  775. pNetBT->OEMEndpointName.Buffer[NETBIOS_NAME_SIZE] = 0;
  776. RtlFreeOemString(&OemEndpoint);
  777. // copy OEM RemoteName
  778. pNetBT->OEMRemoteName.Buffer =
  779. ((PUCHAR)pNetBT->OEMEndpointName.Buffer + pNetBT->OEMEndpointName.MaximumLength);
  780. pNetBT->OEMRemoteName.MaximumLength = NBT_DWORD_ALIGN(remote_len);
  781. if (OemRemote.Length < NETBIOS_NAME_SIZE) {
  782. pNetBT->OEMRemoteName.Length = NETBIOS_NAME_SIZE;
  783. memset (pNetBT->OEMRemoteName.Buffer, ' ', NETBIOS_NAME_SIZE);
  784. CTEMemCopy(pNetBT->OEMRemoteName.Buffer, OemRemote.Buffer, OemRemote.Length);
  785. pNetBT->OEMRemoteName.Buffer[remote_len-1] = 0;
  786. } else {
  787. pNetBT->OEMRemoteName.Length = OemRemote.Length;
  788. CTEMemCopy(pNetBT->OEMRemoteName.Buffer, OemRemote.Buffer, OemRemote.MaximumLength);
  789. }
  790. RtlFreeOemString(&OemRemote);
  791. pNetBT->pNetbiosUnicodeEX = pTA->Address[0].Address;
  792. ppNetBT[0] = p;
  793. return STATUS_SUCCESS;
  794. }
  795. VOID
  796. DeleteInternalAddress(IN PTA_NETBT_INTERNAL_ADDRESS pNetBT)
  797. {
  798. #if 0
  799. PTA_NETBT_INTERNAL_ADDRESS p;
  800. p = CONTAINING_RECORD(pNetBT,PTA_NETBT_INTERNAL_ADDRESS,Address[0].Address);
  801. ASSERT(p->AddressCount == 1);
  802. ASSERT(p->Address[0].AddressLength == sizeof(TDI_ADDRESS_NETBT_INTERNAL));
  803. ASSERT(p->Address[0].AddressType == TDI_ADDRESS_TYPE_UNSPEC);
  804. #endif
  805. if (pNetBT == NULL) {
  806. return;
  807. }
  808. ASSERT(pNetBT->TAAddressCount == 1);
  809. ASSERT(pNetBT->Address[0].AddressLength == sizeof(TA_NETBT_INTERNAL_ADDRESS));
  810. ASSERT(pNetBT->Address[0].AddressType == TDI_ADDRESS_TYPE_UNSPEC);
  811. CTEMemFree(pNetBT);
  812. }
  813. //----------------------------------------------------------------------------
  814. NTSTATUS
  815. NewInternalAddressFromTransportAddress(
  816. IN TRANSPORT_ADDRESS UNALIGNED *pTransportAddress,
  817. IN ULONG MaxInputBufferLength,
  818. OUT PTA_NETBT_INTERNAL_ADDRESS *ppNetBT
  819. )
  820. /*++
  821. Routine Description
  822. This routine handles deciphering the weird transport address syntax
  823. and convert all types of NetBIOS address into one internal format.
  824. Arguments:
  825. Return Values:
  826. NTSTATUS - status of the request
  827. --*/
  828. {
  829. ppNetBT[0] = NULL;
  830. //
  831. // Check for the minimum acceptable length
  832. //
  833. if ((!pTransportAddress) || (MaxInputBufferLength < sizeof (TA_NETBIOS_ADDRESS))) {
  834. ASSERT (0);
  835. return (STATUS_INVALID_ADDRESS);
  836. }
  837. switch (pTransportAddress->Address[0].AddressType)
  838. {
  839. case (TDI_ADDRESS_TYPE_NETBIOS):
  840. return NewInternalAddressFromNetbios(
  841. (PTA_NETBIOS_ADDRESS)pTransportAddress,
  842. MaxInputBufferLength, ppNetBT);
  843. #ifndef VXD
  844. case (TDI_ADDRESS_TYPE_NETBIOS_EX):
  845. return NewInternalAddressFromNetbiosEX(
  846. (PTA_NETBIOS_EX_ADDRESS)pTransportAddress,
  847. MaxInputBufferLength, ppNetBT);
  848. #endif // !VXD
  849. case (TDI_ADDRESS_TYPE_NETBIOS_UNICODE_EX):
  850. return NewInternalAddressFromUnicodeAddress(
  851. (PTA_NETBIOS_UNICODE_EX_ADDRESS)pTransportAddress,
  852. MaxInputBufferLength, ppNetBT);
  853. default:
  854. return (STATUS_INVALID_ADDRESS);
  855. }
  856. if (ppNetBT[0]->Address[0].Address[0].OEMRemoteName.Length > DNS_MAX_NAME_LENGTH) {
  857. DeleteInternalAddress(ppNetBT[0]);
  858. ppNetBT[0] = NULL;
  859. return (STATUS_NAME_TOO_LONG);
  860. }
  861. return (STATUS_SUCCESS);
  862. }
  863. //----------------------------------------------------------------------------
  864. NTSTATUS
  865. GetNetBiosNameFromTransportAddress(
  866. IN TRANSPORT_ADDRESS UNALIGNED *pTransportAddress,
  867. IN ULONG MaxInputBufferLength,
  868. OUT PTDI_ADDRESS_NETBT_INTERNAL pNetBT
  869. )
  870. /*++
  871. Routine Description
  872. This routine handles deciphering the weird transport address syntax
  873. to retrieve the netbios name out of that address.
  874. Arguments:
  875. Return Values:
  876. NTSTATUS - status of the request
  877. --*/
  878. {
  879. //
  880. // Check for the minimum acceptable length
  881. //
  882. if ((!pTransportAddress) ||
  883. (MaxInputBufferLength < sizeof (TA_NETBIOS_ADDRESS)))
  884. {
  885. ASSERT (0);
  886. return (STATUS_INVALID_ADDRESS);
  887. }
  888. CTEZeroMemory(pNetBT, sizeof(pNetBT[0]));
  889. switch (pTransportAddress->Address[0].AddressType)
  890. {
  891. case (TDI_ADDRESS_TYPE_NETBIOS):
  892. return NetbiosAddressToInternalAddress(
  893. (PTA_NETBIOS_ADDRESS)pTransportAddress,
  894. MaxInputBufferLength, pNetBT);
  895. #ifndef VXD
  896. case (TDI_ADDRESS_TYPE_NETBIOS_EX):
  897. return NetbiosEXAddressToInternalAddress(
  898. (PTA_NETBIOS_EX_ADDRESS)pTransportAddress,
  899. MaxInputBufferLength, pNetBT);
  900. #endif // !VXD
  901. default:
  902. {
  903. return (STATUS_INVALID_ADDRESS);
  904. }
  905. }
  906. if (pNetBT->OEMRemoteName.Length > DNS_MAX_NAME_LENGTH)
  907. {
  908. return (STATUS_NAME_TOO_LONG);
  909. }
  910. return (STATUS_SUCCESS);
  911. }
  912. //----------------------------------------------------------------------------
  913. NTSTATUS
  914. ConvertToAscii(
  915. IN PCHAR pNameHdr,
  916. IN LONG NumBytes,
  917. OUT PCHAR pName,
  918. OUT PCHAR *pScope,
  919. OUT PULONG pNameSize
  920. )
  921. /*++
  922. Routine Description:
  923. This routine converts half ascii to normal ascii and then appends the scope
  924. onto the end of the name to make a full name again.
  925. Arguments:
  926. NumBytes - the total number of bytes in the message starting from the
  927. tNETBIOS_NAME structure - may include more than just the name itself
  928. Return Value:
  929. NTSTATUS - success or not
  930. This routine returns the length of the name in half ascii format including
  931. the null at the end, but NOT including the length byte at the beginning.
  932. Thus, for a non-scoped name it would return 33.
  933. It converts the name to ascii and puts 16 bytes into pName, then it returns
  934. pScope as the Ptr to the scope that is still in pNameHdr.
  935. --*/
  936. {
  937. LONG i, ScopeLength, lValue;
  938. ULONG UNALIGNED *pHdr;
  939. // 1st byte is length of the half ascii name, ie 32 (0x20) ==> (Length == 1 byte)
  940. // It should be followed by the half-ascii name ==> (Length == 32 bytes)
  941. // Finally, it has the Scope information ==> (Length >= 1 byte)
  942. //
  943. if ((NumBytes > 1+NETBIOS_NAME_SIZE*2) && (*pNameHdr == NETBIOS_NAME_SIZE*2))
  944. {
  945. pHdr = (ULONG UNALIGNED *)++pNameHdr; // to increment past the length byte
  946. // the Half AScii portion of the netbios name is always 32 bytes long
  947. for (i=0; i < NETBIOS_NAME_SIZE*2 ;i +=4 )
  948. {
  949. lValue = *pHdr - 0x41414141; // four A's
  950. pHdr++;
  951. lValue = ((lValue & 0x0F000000) >> 16) +
  952. ((lValue & 0x000F0000) >> 4) +
  953. ((lValue & 0x00000F00) >> 8) +
  954. ((lValue & 0x0000000F) << 4);
  955. *(PUSHORT)pName = (USHORT)lValue;
  956. ((PUSHORT)pName)++;
  957. }
  958. // verify that the name has the correct format...i.e. it is one or more
  959. // labels each starting with the length byte for the label and the whole
  960. // thing terminated with a 0 byte (for the root node name length of zero).
  961. // count the length of the scope.
  962. // pHdr should be pointing to the first byte after the half ascii name.
  963. // (If there is no scope present, then pHdr must be pointing to the NULL byte)
  964. //
  965. // Also, check for an overflow on the maximum length of 256 bytes
  966. if ((STATUS_SUCCESS != (strnlen ((PUCHAR)pHdr, NumBytes-(1+NETBIOS_NAME_SIZE*2), &ScopeLength))) ||
  967. (ScopeLength > ((MAX_SCOPE_LENGTH+1)-NETBIOS_NAME_SIZE)))
  968. {
  969. // the name is too long..probably badly formed
  970. return(STATUS_UNSUCCESSFUL);
  971. }
  972. // Store the address of the start of the scope in the netbios name
  973. // (if one is present).
  974. //
  975. *pScope = (PUCHAR)pHdr;
  976. *pNameSize = NETBIOS_NAME_SIZE*2 + ScopeLength + 1; // include the null at the end.
  977. return(STATUS_SUCCESS);
  978. }
  979. else
  980. {
  981. return(STATUS_UNSUCCESSFUL);
  982. }
  983. }
  984. //----------------------------------------------------------------------------
  985. PCHAR
  986. ConvertToHalfAscii(
  987. OUT PCHAR pDest,
  988. IN PCHAR pName,
  989. IN PCHAR pScope,
  990. IN ULONG uScopeSize
  991. )
  992. /*++
  993. Routine Description:
  994. This routine converts ascii to half ascii and appends the scope on the
  995. end
  996. Arguments:
  997. Return Value:
  998. the address of the next byte in the destination after the the name
  999. has been converted and copied
  1000. --*/
  1001. {
  1002. LONG i;
  1003. // the first byte of the name is the length field = 2*16
  1004. *pDest++ = ((UCHAR)NETBIOS_NAME_SIZE << 1);
  1005. // step through name converting ascii to half ascii, for 32 times
  1006. for (i=0; i < NETBIOS_NAME_SIZE ;i++ )
  1007. {
  1008. *pDest++ = ((UCHAR)*pName >> 4) + 'A';
  1009. *pDest++ = (*pName++ & 0x0F) + 'A';
  1010. }
  1011. //
  1012. // put the length of the scope into the next byte followed by the
  1013. // scope itself. For 1 length scopes (the normal case), writing
  1014. // the zero(for the end of the scope is all that is needed).
  1015. //
  1016. if (uScopeSize > 1)
  1017. {
  1018. CTEMemCopy(pDest,pScope,uScopeSize);
  1019. pDest = pDest + uScopeSize;
  1020. }
  1021. else
  1022. {
  1023. *pDest++ = 0;
  1024. }
  1025. // return the address of the next byte of the destination
  1026. return(pDest);
  1027. }
  1028. //----------------------------------------------------------------------------
  1029. ULONG
  1030. Nbt_inet_addr(
  1031. IN PCHAR pName,
  1032. IN ULONG Flags
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. This routine converts ascii ipaddr (11.101.4.25) into a ULONG. This is
  1037. based on the inet_addr code in winsock
  1038. Arguments:
  1039. pName - the string containing the ipaddress
  1040. Return Value:
  1041. the ipaddress as a ULONG if it's a valid ipaddress. Otherwise, 0.
  1042. --*/
  1043. {
  1044. PCHAR pStr;
  1045. int i;
  1046. int len, fieldLen;
  1047. int fieldsDone;
  1048. ULONG IpAddress;
  1049. BYTE ByteVal;
  1050. PCHAR pIpPtr;
  1051. BOOLEAN fDotFound;
  1052. BOOLEAN fieldOk;
  1053. pStr = pName;
  1054. len = 0;
  1055. pIpPtr = (PCHAR)&IpAddress;
  1056. pIpPtr += 3; // so that we store in network order
  1057. fieldsDone=0;
  1058. //
  1059. // the 11.101.4.25 format can be atmost 15 chars, and pName is guaranteed
  1060. // to be at least 16 chars long (how convenient!!). Convert the string to
  1061. // a ULONG.
  1062. //
  1063. while(len < NETBIOS_NAME_SIZE)
  1064. {
  1065. fieldLen=0;
  1066. fieldOk = FALSE;
  1067. ByteVal = 0;
  1068. fDotFound = FALSE;
  1069. //
  1070. // This loop traverses each of the four fields (max len of each
  1071. // field is 3, plus 1 for the '.'
  1072. //
  1073. while (fieldLen < 4)
  1074. {
  1075. if ((*pStr >='0') && (*pStr <='9'))
  1076. {
  1077. //
  1078. // No Byte value should be greater than 255!
  1079. // Bug#: 10487
  1080. //
  1081. if ((ByteVal > 25) ||
  1082. ((ByteVal == 25) && (*pStr > '5')))
  1083. {
  1084. return (0);
  1085. }
  1086. ByteVal = (ByteVal*10) + (*pStr - '0');
  1087. fieldOk = TRUE;
  1088. }
  1089. else if ((*pStr == '.') || (*pStr == ' ') || (*pStr == '\0'))
  1090. {
  1091. *pIpPtr = ByteVal;
  1092. pIpPtr--;
  1093. fieldsDone++;
  1094. if (*pStr == '.')
  1095. {
  1096. fDotFound = TRUE;
  1097. }
  1098. else // (*pStr == ' ') || (*pStr == '\0')
  1099. {
  1100. // if we got a space or 0, assume it's the 4th field
  1101. break;
  1102. }
  1103. }
  1104. else // unacceptable char: can't be ipaddr
  1105. {
  1106. return(0);
  1107. }
  1108. pStr++;
  1109. len++;
  1110. fieldLen++;
  1111. // if we found the dot, we are done with this field: go to the next one
  1112. if (fDotFound)
  1113. break;
  1114. }
  1115. // this field wasn't ok (e.g. "11.101..4" or "11.101.4." etc.)
  1116. if (!fieldOk)
  1117. {
  1118. return(0);
  1119. }
  1120. // if we are done with all 4 fields, we are done with the outer loop too
  1121. if ( fieldsDone == 4)
  1122. break;
  1123. if (!fDotFound)
  1124. {
  1125. return(0);
  1126. }
  1127. }
  1128. //
  1129. // make sure the remaining NETBIOS_NAME_SIZE-1 chars are spaces or 0's
  1130. // (i.e. don't allow 11.101.4.25xyz to succeed)
  1131. //
  1132. for (i=len; i<NETBIOS_NAME_SIZE-1; i++, pStr++)
  1133. {
  1134. if (*pStr != ' ' && *pStr != '\0')
  1135. {
  1136. return(0);
  1137. }
  1138. }
  1139. if ((Flags & (SESSION_SETUP_FLAG|REMOTE_ADAPTER_STAT_FLAG)) &&
  1140. (!(IS_UNIQUE_ADDR(IpAddress))))
  1141. {
  1142. KdPrint (("Nbt.Nbt_inet_addr: Address=<%15.15s> is not unique!\n", pName));
  1143. IpAddress = 0;
  1144. }
  1145. return( IpAddress );
  1146. }
  1147. //----------------------------------------------------------------------------
  1148. tDGRAM_SEND_TRACKING *
  1149. NbtAllocInitTracker(
  1150. IN tDGRAM_SEND_TRACKING *pTracker
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. This routine allocates memory for several of the structures attached to
  1155. the dgram tracking list, so that this memory does not need to be
  1156. allocated and freed for each send.
  1157. Arguments:
  1158. ppListHead - a ptr to a ptr to the list head
  1159. Return Value:
  1160. none
  1161. --*/
  1162. {
  1163. PLIST_ENTRY pEntry;
  1164. PTRANSPORT_ADDRESS pTransportAddr;
  1165. ULONG TotalSize;
  1166. TotalSize = sizeof(tDGRAM_SEND_TRACKING)
  1167. + sizeof(TDI_CONNECTION_INFORMATION)
  1168. + sizeof(TRANSPORT_ADDRESS) -1
  1169. + NbtConfig.SizeTransportAddress;
  1170. //
  1171. // If not Tracker was provided, then we will have to allocate one!
  1172. //
  1173. if (!pTracker)
  1174. {
  1175. //
  1176. // allocate all the tracker memory as one block and then divy it up later
  1177. // into the various buffers
  1178. //
  1179. if (pTracker = (tDGRAM_SEND_TRACKING *) NbtAllocMem (TotalSize, NBT_TAG2('07')))
  1180. {
  1181. NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER]++;
  1182. }
  1183. }
  1184. if (pTracker)
  1185. {
  1186. CTEZeroMemory(pTracker,TotalSize);
  1187. pTracker->Verify = NBT_VERIFY_TRACKER;
  1188. pTracker->RefCount = 1;
  1189. InitializeListHead (&pTracker->Linkage);
  1190. InitializeListHead (&pTracker->TrackerList); // Empty the list of trackers linked to this one
  1191. pTracker->pSendInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)pTracker + sizeof(tDGRAM_SEND_TRACKING));
  1192. // fill in the connection information - especially the Remote address structure
  1193. pTracker->pSendInfo->RemoteAddressLength = sizeof(TRANSPORT_ADDRESS) -1
  1194. + pNbtGlobConfig->SizeTransportAddress;
  1195. // allocate the remote address structure
  1196. pTransportAddr = (PTRANSPORT_ADDRESS) ((PUCHAR)pTracker->pSendInfo
  1197. + sizeof(TDI_CONNECTION_INFORMATION));
  1198. // fill in the remote address
  1199. pTransportAddr->TAAddressCount = 1;
  1200. pTransportAddr->Address[0].AddressLength = NbtConfig.SizeTransportAddress;
  1201. pTransportAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1202. ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->sin_port = NBT_NAMESERVICE_UDP_PORT;
  1203. ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->in_addr = 0L;
  1204. // put a ptr to this address structure into the sendinfo structure
  1205. pTracker->pSendInfo->RemoteAddress = (PVOID)pTransportAddr;
  1206. }
  1207. return(pTracker);
  1208. }
  1209. //----------------------------------------------------------------------------
  1210. #define MAX_FREE_TRACKERS 50
  1211. ULONG NumFreeTrackers = 0;
  1212. // #if DBG
  1213. ULONG TrackTrackers[NBT_TRACKER_NUM_TRACKER_TYPES];
  1214. ULONG TrackerHighWaterMark[NBT_TRACKER_NUM_TRACKER_TYPES];
  1215. // #endif // DBG
  1216. NTSTATUS
  1217. GetTracker(
  1218. OUT tDGRAM_SEND_TRACKING **ppTracker,
  1219. IN enum eTRACKER_TYPE TrackerType)
  1220. /*++
  1221. Routine Description:
  1222. This Routine gets a Tracker data structure to track sending a datagram
  1223. or session packet.
  1224. Arguments:
  1225. Return Value:
  1226. Status - STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  1227. --*/
  1228. {
  1229. PLIST_ENTRY pListEntry;
  1230. CTELockHandle OldIrq;
  1231. tDGRAM_SEND_TRACKING *pTracker = NULL;
  1232. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1233. CTESpinLock(&NbtConfig,OldIrq);
  1234. if (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ))
  1235. {
  1236. pListEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ);
  1237. pTracker = CONTAINING_RECORD(pListEntry,tDGRAM_SEND_TRACKING,Linkage);
  1238. NumFreeTrackers--;
  1239. }
  1240. else if (NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER] >= NbtConfig.iMaxNumBuff[eNBT_DGRAM_TRACKER])
  1241. {
  1242. CTESpinFree(&NbtConfig,OldIrq);
  1243. KdPrint(("GetTracker: WARNING: Tracker leak -- Failing request!\n")) ;
  1244. *ppTracker = NULL;
  1245. return (status);
  1246. }
  1247. if (pTracker = NbtAllocInitTracker (pTracker))
  1248. {
  1249. // #if DBG
  1250. pTracker->TrackerType = TrackerType;
  1251. InsertTailList (&UsedTrackers, &pTracker->DebugLinkage); // keep tracker on a used list for debug
  1252. TrackTrackers[TrackerType]++;
  1253. if (TrackTrackers[TrackerType] > TrackerHighWaterMark[TrackerType])
  1254. {
  1255. TrackerHighWaterMark[TrackerType] = TrackTrackers[TrackerType];
  1256. }
  1257. // #endif
  1258. status = STATUS_SUCCESS;
  1259. }
  1260. CTESpinFree(&NbtConfig,OldIrq);
  1261. *ppTracker = pTracker;
  1262. return (status);
  1263. }
  1264. //----------------------------------------------------------------------------
  1265. VOID
  1266. FreeTracker(
  1267. IN tDGRAM_SEND_TRACKING *pTracker,
  1268. IN ULONG Actions
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This routine cleans up a Tracker block and puts it back on the free
  1273. queue.
  1274. Arguments:
  1275. Return Value:
  1276. NTSTATUS - success or not
  1277. --*/
  1278. {
  1279. CTELockHandle OldIrq;
  1280. PLIST_ENTRY pListEntry;
  1281. CTESpinLock(&NbtConfig,OldIrq);
  1282. //
  1283. CHECK_PTR(pTracker);
  1284. if (!NBT_VERIFY_HANDLE(pTracker, NBT_VERIFY_TRACKER)) // Bad pointer -- don't mess with it!
  1285. {
  1286. CTESpinFree(&NbtConfig,OldIrq);
  1287. DbgPrint("Nbt.FreeTracker: ERROR! Bad Tracker ptr @<%p>\n", pTracker);
  1288. ASSERT(0);
  1289. return;
  1290. }
  1291. if (Actions & REMOVE_LIST)
  1292. {
  1293. //
  1294. // unlink the tracker block from the NodeStatus Q
  1295. RemoveEntryList(&pTracker->Linkage);
  1296. }
  1297. if (Actions & FREE_HDR)
  1298. {
  1299. // return the datagram hdr to the free pool
  1300. //
  1301. if (pTracker->SendBuffer.pDgramHdr)
  1302. {
  1303. CTEMemFree((PVOID)pTracker->SendBuffer.pDgramHdr);
  1304. }
  1305. // Free the RemoteName storage
  1306. //
  1307. if (pTracker->pRemoteName)
  1308. {
  1309. CTEMemFree((PVOID)pTracker->pRemoteName);
  1310. pTracker->pRemoteName = NULL;
  1311. }
  1312. if (pTracker->UnicodeRemoteName) {
  1313. CTEMemFree((PVOID)pTracker->UnicodeRemoteName);
  1314. pTracker->UnicodeRemoteName = NULL;
  1315. }
  1316. }
  1317. #ifdef MULTIPLE_WINS
  1318. if (pTracker->pFailedIpAddresses)
  1319. {
  1320. CTEMemFree((PVOID)pTracker->pFailedIpAddresses);
  1321. pTracker->pFailedIpAddresses = NULL;
  1322. }
  1323. #endif
  1324. if (pTracker->IpList)
  1325. {
  1326. ASSERT(pTracker->NumAddrs);
  1327. CTEMemFree(pTracker->IpList);
  1328. }
  1329. ASSERT (IsListEmpty (&pTracker->TrackerList));
  1330. InitializeListHead(&pTracker->TrackerList);
  1331. InsertTailList (&NbtConfig.DgramTrackerFreeQ, &pTracker->Linkage);
  1332. pTracker->Verify = NBT_VERIFY_TRACKER_DOWN;
  1333. // #IF DBG
  1334. TrackTrackers[pTracker->TrackerType]--;
  1335. RemoveEntryList(&pTracker->DebugLinkage);
  1336. // #endif // DBG
  1337. if (NumFreeTrackers > MAX_FREE_TRACKERS)
  1338. {
  1339. //
  1340. // We already have the required # of free trackers available
  1341. // in our pool, so just free the oldest Tracker
  1342. //
  1343. pListEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ);
  1344. pTracker = CONTAINING_RECORD(pListEntry,tDGRAM_SEND_TRACKING,Linkage);
  1345. CTEMemFree (pTracker);
  1346. NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER]--;
  1347. }
  1348. else
  1349. {
  1350. NumFreeTrackers++;
  1351. }
  1352. CTESpinFree(&NbtConfig,OldIrq);
  1353. }
  1354. //----------------------------------------------------------------------------
  1355. NTSTATUS
  1356. NbtInitTrackerQ(
  1357. LONG iNumBuffers
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. This routine allocates memory blocks for doubly linked lists and links
  1362. them to a list.
  1363. Arguments:
  1364. ppListHead - a ptr to a ptr to the list head to add buffer to
  1365. iNumBuffers - the number of buffers to add to the queue
  1366. Return Value:
  1367. none
  1368. --*/
  1369. {
  1370. int i;
  1371. tDGRAM_SEND_TRACKING *pTracker;
  1372. for (i=0; i<iNumBuffers; i++)
  1373. {
  1374. pTracker = NbtAllocInitTracker (NULL);
  1375. if (!pTracker)
  1376. {
  1377. return(STATUS_INSUFFICIENT_RESOURCES);
  1378. }
  1379. else
  1380. {
  1381. InsertTailList (&NbtConfig.DgramTrackerFreeQ, &pTracker->Linkage);
  1382. NumFreeTrackers++;
  1383. }
  1384. }
  1385. return(STATUS_SUCCESS);
  1386. }
  1387. //----------------------------------------------------------------------------
  1388. #ifndef VXD
  1389. NTSTATUS
  1390. GetIrp(
  1391. OUT PIRP *ppIrp)
  1392. /*++
  1393. Routine Description:
  1394. This Routine gets an Irp from the free queue or it allocates another one
  1395. the queue is empty.
  1396. Arguments:
  1397. Return Value:
  1398. BOOLEAN - TRUE if IRQL is too high
  1399. --*/
  1400. {
  1401. PLIST_ENTRY pListEntry;
  1402. NTSTATUS status;
  1403. CTELockHandle OldIrq;
  1404. tDEVICECONTEXT *pDeviceContext;
  1405. PIRP pIrp;
  1406. // get an Irp from the list
  1407. CTESpinLock(&NbtConfig,OldIrq);
  1408. status = STATUS_SUCCESS;
  1409. if (!IsListEmpty(&NbtConfig.IrpFreeList))
  1410. {
  1411. pListEntry = RemoveHeadList(&NbtConfig.IrpFreeList);
  1412. *ppIrp = CONTAINING_RECORD(pListEntry,IRP,Tail.Overlay.ListEntry);
  1413. }
  1414. else
  1415. {
  1416. // check if we are allowed to allocate more memory blocks
  1417. if (NbtConfig.iCurrentNumBuff[eNBT_FREE_IRPS] >= NbtConfig.iMaxNumBuff[eNBT_FREE_IRPS] )
  1418. {
  1419. status = STATUS_INSUFFICIENT_RESOURCES;
  1420. }
  1421. else
  1422. {
  1423. // use the first device in the list of adapter since we need to know
  1424. // the stack size of the Irp we are creating. It is possible to
  1425. // get here before we have put the first device on the context Q,
  1426. // especially for proxy operation, so check if the list is empty
  1427. // or not first.
  1428. //
  1429. if (IsListEmpty(&NbtConfig.DeviceContexts))
  1430. {
  1431. status = STATUS_INSUFFICIENT_RESOURCES;
  1432. }
  1433. else
  1434. {
  1435. pListEntry = NbtConfig.DeviceContexts.Flink;
  1436. pDeviceContext = CONTAINING_RECORD(pListEntry,tDEVICECONTEXT,Linkage);
  1437. if (!(pIrp = NTAllocateNbtIrp(&pDeviceContext->DeviceObject)))
  1438. {
  1439. status = STATUS_INSUFFICIENT_RESOURCES;
  1440. }
  1441. else
  1442. {
  1443. *ppIrp = pIrp;
  1444. //
  1445. // Irp allocated - Increment the #
  1446. //
  1447. NbtConfig.iCurrentNumBuff[eNBT_FREE_IRPS]++;
  1448. }
  1449. }
  1450. }
  1451. }
  1452. CTESpinFree(&NbtConfig,OldIrq);
  1453. //#if DBG
  1454. if (status == STATUS_SUCCESS)
  1455. {
  1456. ADD_TO_LIST(&UsedIrps,&(*ppIrp)->ThreadListEntry);
  1457. }
  1458. //#endif
  1459. return(status);
  1460. }
  1461. #endif //!VXD
  1462. //----------------------------------------------------------------------------
  1463. ULONG
  1464. CountLocalNames(IN tNBTCONFIG *pNbtConfig
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. This Routine counts the number of names in the local name table.
  1469. Arguments:
  1470. Return Value:
  1471. ULONG - the number of names
  1472. --*/
  1473. {
  1474. PLIST_ENTRY pHead;
  1475. PLIST_ENTRY pEntry;
  1476. ULONG Count;
  1477. tNAMEADDR *pNameAddr;
  1478. LONG i;
  1479. Count = 0;
  1480. for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
  1481. {
  1482. pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
  1483. pEntry = pHead;
  1484. while ((pEntry = pEntry->Flink) != pHead)
  1485. {
  1486. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  1487. //
  1488. // don't want unresolved names, or the broadcast name
  1489. //
  1490. if (!(pNameAddr->NameTypeState & STATE_RESOLVING) &&
  1491. (pNameAddr->Name[0] != '*'))
  1492. {
  1493. Count++;
  1494. }
  1495. }
  1496. }
  1497. return(Count);
  1498. }
  1499. //----------------------------------------------------------------------------
  1500. ULONG
  1501. CountUpperConnections(
  1502. IN tDEVICECONTEXT *pDeviceContext
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. This Routine counts the number of upper connections that have been created
  1507. in preparation for creating an equivalent number of lower connections.
  1508. Arguments:
  1509. Return Value:
  1510. ULONG - the number of names
  1511. --*/
  1512. {
  1513. PLIST_ENTRY pHead;
  1514. PLIST_ENTRY pEntry;
  1515. PLIST_ENTRY pClientHead;
  1516. PLIST_ENTRY pConnHead;
  1517. PLIST_ENTRY pClientEntry;
  1518. PLIST_ENTRY pConnEntry;
  1519. ULONG CountConnections = 0;
  1520. tADDRESSELE *pAddressEle;
  1521. tCLIENTELE *pClient;
  1522. tCONNECTELE *pConnEle;
  1523. CTELockHandle OldIrq1, OldIrq2, OldIrq3;
  1524. //
  1525. // Need to hold JointLock before accessing AddressHead!
  1526. //
  1527. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1528. // get the list of addresses for this device
  1529. pHead = &NbtConfig.AddressHead;
  1530. pEntry = pHead->Flink;
  1531. while (pEntry != pHead)
  1532. {
  1533. pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
  1534. //
  1535. // Need to hold pAddressEle lock before accessing ClientHead!
  1536. //
  1537. CTESpinLock(pAddressEle,OldIrq2);
  1538. pClientHead = &pAddressEle->ClientHead;
  1539. pClientEntry = pClientHead->Flink;
  1540. while (pClientEntry != pClientHead)
  1541. {
  1542. pClient = CONTAINING_RECORD(pClientEntry,tCLIENTELE,Linkage);
  1543. //
  1544. // Need to hold pClient lock before accessing ConnectHead!
  1545. //
  1546. CTESpinLock(pClient, OldIrq3);
  1547. pConnHead = &pClient->ConnectHead;
  1548. pConnEntry = pConnHead->Flink;
  1549. while (pConnEntry != pConnHead)
  1550. {
  1551. pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage);
  1552. if (pConnEle->pDeviceContext == pDeviceContext)
  1553. {
  1554. CountConnections++;
  1555. }
  1556. pConnEntry = pConnEntry->Flink;
  1557. }
  1558. CTESpinFree(pClient, OldIrq3);
  1559. pClientEntry = pClientEntry->Flink;
  1560. }
  1561. CTESpinFree(pAddressEle, OldIrq2);
  1562. pEntry = pEntry->Flink;
  1563. }
  1564. CTESpinFree(&NbtConfig.JointLock, OldIrq1);
  1565. return(CountConnections);
  1566. }
  1567. //----------------------------------------------------------------------------
  1568. NTSTATUS
  1569. DisableInboundConnections(
  1570. IN tDEVICECONTEXT *pDeviceContext
  1571. )
  1572. /*++
  1573. Routine Description:
  1574. This routine checks the devicecontext for open connections and sets
  1575. the Lower Connection free list to empty.
  1576. Arguments:
  1577. Return Value:
  1578. none
  1579. --*/
  1580. {
  1581. CTELockHandle OldIrqJoint;
  1582. CTELockHandle OldIrqDevice;
  1583. CTELockHandle OldIrqConn;
  1584. CTELockHandle OldIrqLower;
  1585. tLOWERCONNECTION *pLowerConn;
  1586. NTSTATUS status;
  1587. PVOID ConnectContext;
  1588. CTESpinLock(&NbtConfig.JointLock,OldIrqJoint);
  1589. CTESpinLock(pDeviceContext,OldIrqDevice);
  1590. //
  1591. // First take care of the free connections
  1592. //
  1593. while (!IsListEmpty (&pDeviceContext->LowerConnFreeHead))
  1594. {
  1595. pLowerConn = CONTAINING_RECORD (pDeviceContext->LowerConnFreeHead.Flink,tLOWERCONNECTION,Linkage);
  1596. RemoveEntryList (&pLowerConn->Linkage);
  1597. InitializeListHead (&pLowerConn->Linkage);
  1598. //
  1599. // close the lower connection with the transport
  1600. //
  1601. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, TRUE);
  1602. InterlockedDecrement (&pDeviceContext->NumFreeLowerConnections);
  1603. }
  1604. ASSERT (pDeviceContext->NumFreeLowerConnections == 0);
  1605. //
  1606. // Now go through the list of Inbound connections and cleanup!
  1607. //
  1608. while (!IsListEmpty (&pDeviceContext->WaitingForInbound))
  1609. {
  1610. pLowerConn = CONTAINING_RECORD(pDeviceContext->WaitingForInbound.Flink,tLOWERCONNECTION,Linkage);
  1611. RemoveEntryList (&pLowerConn->Linkage);
  1612. InitializeListHead (&pLowerConn->Linkage);
  1613. SET_STATE_LOWER(pLowerConn, NBT_IDLE); // so that Inbound doesn't start processing it!
  1614. if (pLowerConn->SpecialAlloc)
  1615. {
  1616. InterlockedDecrement(&pLowerConn->pDeviceContext->NumSpecialLowerConn);
  1617. }
  1618. ASSERT (pLowerConn->RefCount == 2);
  1619. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, TRUE); // RefCount will go to 1
  1620. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, TRUE);// This should close all the Tcp handles
  1621. InterlockedDecrement (&pDeviceContext->NumWaitingForInbound);
  1622. }
  1623. ASSERT (pDeviceContext->NumWaitingForInbound == 0);
  1624. // ******************************************
  1625. // NOTE: The code after this point can probably be deleted
  1626. // because TCP should disconnect all open connections when it
  1627. // is notified of the address change. Just use this code for test.
  1628. //
  1629. //
  1630. // Now go through the list of active Lower connections to see which are
  1631. // still up and issue disconnects on them.
  1632. //
  1633. while (!IsListEmpty (&pDeviceContext->LowerConnection))
  1634. {
  1635. pLowerConn = CONTAINING_RECORD (pDeviceContext->LowerConnection.Flink,tLOWERCONNECTION,Linkage);
  1636. RemoveEntryList (&pLowerConn->Linkage);
  1637. InitializeListHead (&pLowerConn->Linkage);
  1638. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_DISABLE_INBOUND);
  1639. CTESpinFree(pDeviceContext,OldIrqDevice);
  1640. CTESpinFree(&NbtConfig.JointLock,OldIrqJoint);
  1641. CTESpinLock(pLowerConn,OldIrqLower);
  1642. //
  1643. // In the connecting state the TCP connection is being
  1644. // setup.
  1645. //
  1646. if ((pLowerConn->State == NBT_SESSION_UP) ||
  1647. (pLowerConn->State == NBT_CONNECTING))
  1648. {
  1649. tCLIENTELE *pClientEle;
  1650. tCONNECTELE *pConnEle;
  1651. if (pLowerConn->State == NBT_CONNECTING)
  1652. {
  1653. // CleanupAfterDisconnect expects this ref count
  1654. // to be 2, meaning that it got connected, so increment
  1655. // here
  1656. NBT_REFERENCE_LOWERCONN(pLowerConn, REF_LOWC_CONNECTED);
  1657. }
  1658. pClientEle = pLowerConn->pUpperConnection->pClientEle;
  1659. pConnEle = pLowerConn->pUpperConnection;
  1660. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  1661. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTING);
  1662. SET_STATE_UPPER (pConnEle, NBT_DISCONNECTED);
  1663. SetStateProc(pLowerConn,RejectAnyData);
  1664. CTESpinFree(pLowerConn,OldIrqLower);
  1665. ConnectContext = pConnEle->ConnectContext;
  1666. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  1667. if (pClientEle->evDisconnect)
  1668. {
  1669. status = (*pClientEle->evDisconnect)(pClientEle->DiscEvContext,
  1670. ConnectContext,
  1671. 0,
  1672. NULL,
  1673. 0,
  1674. NULL,
  1675. TDI_DISCONNECT_ABORT);
  1676. }
  1677. // this should kill of the connection when the irp
  1678. // completes by calling CleanupAfterDisconnect.
  1679. //
  1680. #ifndef VXD
  1681. status = DisconnectLower(pLowerConn,
  1682. NBT_SESSION_UP,
  1683. TDI_DISCONNECT_ABORT,
  1684. &DefaultDisconnectTimeout,
  1685. TRUE);
  1686. #else
  1687. // Vxd can't wait for the disconnect
  1688. status = DisconnectLower(pLowerConn,
  1689. NBT_SESSION_UP,
  1690. TDI_DISCONNECT_ABORT,
  1691. &DefaultDisconnectTimeout,
  1692. FALSE);
  1693. #endif
  1694. }
  1695. else if (pLowerConn->State == NBT_IDLE)
  1696. {
  1697. tCONNECTELE *pConnEle;
  1698. CTESpinFree(pLowerConn,OldIrqLower);
  1699. CTESpinLock(&NbtConfig.JointLock,OldIrqJoint);
  1700. if (pConnEle = pLowerConn->pUpperConnection)
  1701. {
  1702. CTESpinLock(pConnEle,OldIrqConn);
  1703. //
  1704. // this makes a best effort to find the connection and
  1705. // and cancel it. Anything not cancelled will eventually
  1706. // fail with a bad ret code from the transport which is
  1707. // ok too.
  1708. //
  1709. status = CleanupConnectingState(pConnEle,pDeviceContext, &OldIrqConn,&OldIrqLower);
  1710. CTESpinFree(pConnEle,OldIrqConn);
  1711. }
  1712. CTESpinFree(&NbtConfig.JointLock,OldIrqJoint);
  1713. }
  1714. else
  1715. {
  1716. CTESpinFree(pLowerConn,OldIrqLower);
  1717. }
  1718. CTESpinLock(&NbtConfig.JointLock,OldIrqJoint);
  1719. CTESpinLock(pDeviceContext,OldIrqDevice);
  1720. //
  1721. // remove the reference added above when the list was
  1722. // created.
  1723. //
  1724. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_DISABLE_INBOUND, TRUE);
  1725. }
  1726. CTESpinFree(pDeviceContext,OldIrqDevice);
  1727. CTESpinFree(&NbtConfig.JointLock,OldIrqJoint);
  1728. return(STATUS_SUCCESS);
  1729. }
  1730. //----------------------------------------------------------------------------
  1731. NTSTATUS
  1732. ReRegisterLocalNames(
  1733. IN tDEVICECONTEXT *pDeviceContext,
  1734. IN BOOLEAN fSendNameRelease
  1735. )
  1736. /*++
  1737. Routine Description:
  1738. This routine re-registers names with WINS when DHCP changes the IP
  1739. address.
  1740. Arguments:
  1741. pDeviceContext - ptr to the devicecontext
  1742. Return Value:
  1743. status
  1744. --*/
  1745. {
  1746. NTSTATUS status;
  1747. tTIMERQENTRY *pTimerEntry;
  1748. CTELockHandle OldIrq;
  1749. LONG i;
  1750. PLIST_ENTRY pHead;
  1751. PLIST_ENTRY pEntry;
  1752. PLIST_ENTRY pHead1;
  1753. PLIST_ENTRY pEntry1;
  1754. PLIST_ENTRY pHead2;
  1755. PLIST_ENTRY pEntry2;
  1756. tDEVICECONTEXT *pRelDeviceContext;
  1757. tDEVICECONTEXT *pSrcIpDeviceContext;
  1758. tNAMEADDR *pNameAddr;
  1759. tDGRAM_SEND_TRACKING *pTracker = NULL;
  1760. CTEULONGLONG ReRegisterMask;
  1761. CTESystemTime CurrentTime;
  1762. IF_DBG(NBT_DEBUG_NAMESRV)
  1763. KdPrint (("Nbt.ReRegisterLocalNames Called on Device=<%x>...\n",
  1764. pDeviceContext));
  1765. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1766. if (fSendNameRelease)
  1767. {
  1768. CTEQuerySystemTime (CurrentTime);
  1769. if (((CurrentTime.QuadPart-NbtConfig.LastForcedReleaseTime.QuadPart)
  1770. <= (TWO_MINUTES*10000)) || // Check in 100 nanosec units
  1771. (!(NT_SUCCESS(GetTracker(&pTracker,NBT_TRACKER_RELEASE_REFRESH)))))
  1772. {
  1773. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1774. IF_DBG(NBT_DEBUG_NAMESRV)
  1775. KdPrint (("Nbt.ReRegisterLocalNames: ERROR: Name Release -- last Release interval=<%d>Secs\n",
  1776. (LONG) ((CurrentTime.QuadPart-NbtConfig.LastForcedReleaseTime.QuadPart)/(1000*10000))));
  1777. return (STATUS_IO_TIMEOUT);
  1778. }
  1779. NbtConfig.LastForcedReleaseTime = CurrentTime;
  1780. }
  1781. if (pTimerEntry = NbtConfig.pRefreshTimer)
  1782. {
  1783. NbtConfig.pRefreshTimer = NULL;
  1784. status = StopTimer(pTimerEntry,NULL,NULL);
  1785. }
  1786. //
  1787. // restart timer and use
  1788. // the initial refresh rate until we can contact the name server
  1789. //
  1790. NbtConfig.MinimumTtl = NbtConfig.InitialRefreshTimeout;
  1791. NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
  1792. //
  1793. // set this to 3 so that refreshBegin will refresh to the primary and
  1794. // then switch to backup on the next refresh interval if it doesn't
  1795. // get through.
  1796. //
  1797. NbtConfig.sTimeoutCount = 3;
  1798. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  1799. status = StartTimer(RefreshTimeout,
  1800. NbtConfig.InitialRefreshTimeout/NbtConfig.RefreshDivisor,
  1801. NULL, // context value
  1802. NULL, // context2 value
  1803. NULL,
  1804. NULL,
  1805. NULL, // This is a Global Timer!
  1806. &pTimerEntry,
  1807. 0,
  1808. TRUE);
  1809. if ( !NT_SUCCESS( status ) )
  1810. {
  1811. if (pTracker)
  1812. {
  1813. FreeTracker(pTracker, RELINK_TRACKER);
  1814. }
  1815. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1816. return status ;
  1817. }
  1818. NbtConfig.pRefreshTimer = pTimerEntry;
  1819. //
  1820. // If a Device was specified to ReRegister on, then Zero out only the
  1821. // bit for this Device in the RefreshMask for each name
  1822. // otherwise, ReRegister on all Devices (Zero out all bits!)
  1823. //
  1824. if (pDeviceContext)
  1825. {
  1826. ReRegisterMask = ~pDeviceContext->AdapterMask; // Only bit for this Device is 0
  1827. pDeviceContext->DeviceRefreshState &= ~NBT_D_REFRESHING_NOW;
  1828. }
  1829. else
  1830. {
  1831. ReRegisterMask = 0;
  1832. }
  1833. for (i=0 ;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
  1834. {
  1835. pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
  1836. pEntry = pHead->Flink;
  1837. while (pEntry != pHead)
  1838. {
  1839. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  1840. //
  1841. // set so that nextrefresh finds the name and does a refresh
  1842. //
  1843. if (!(pNameAddr->NameTypeState & STATE_RESOLVED) ||
  1844. (pNameAddr->Name[0] == '*') ||
  1845. (pNameAddr->NameTypeState & NAMETYPE_QUICK))
  1846. {
  1847. pEntry = pEntry->Flink;
  1848. continue;
  1849. }
  1850. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_RELEASE_REFRESH);
  1851. if (fSendNameRelease)
  1852. {
  1853. IF_DBG(NBT_DEBUG_NAMESRV)
  1854. KdPrint(("Nbt.ReRegisterLocalNames: Name=<%16.16s:%x>\n",
  1855. pNameAddr->Name,pNameAddr->Name[15]));
  1856. pTracker->pNameAddr = pNameAddr;
  1857. //
  1858. // Release this name on all the devices (brute force method)!
  1859. //
  1860. pHead1 = &NbtConfig.DeviceContexts;
  1861. pEntry1 = pHead1->Flink;
  1862. while (pEntry1 != pHead1)
  1863. {
  1864. pSrcIpDeviceContext = CONTAINING_RECORD(pEntry1,tDEVICECONTEXT,Linkage);
  1865. if ((pSrcIpDeviceContext->IpAddress == 0) ||
  1866. (!NBT_REFERENCE_DEVICE (pSrcIpDeviceContext, REF_DEV_REREG, TRUE)))
  1867. {
  1868. pEntry1 = pEntry1->Flink;
  1869. continue;
  1870. }
  1871. pHead2 = &NbtConfig.DeviceContexts;
  1872. pEntry2 = pHead2->Flink;
  1873. while (pEntry2 != pHead2)
  1874. {
  1875. //
  1876. // See if we need to release on this device
  1877. //
  1878. pRelDeviceContext = CONTAINING_RECORD(pEntry2,tDEVICECONTEXT,Linkage);
  1879. if ((pRelDeviceContext->IpAddress == 0) ||
  1880. (!NBT_REFERENCE_DEVICE (pRelDeviceContext, REF_DEV_REREG, TRUE)))
  1881. {
  1882. pEntry2 = pEntry2->Flink;
  1883. continue;
  1884. }
  1885. //
  1886. // Send the NameRelease to the Primary and Secondary Wins!
  1887. //
  1888. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1889. pTracker->pDeviceContext = pRelDeviceContext;
  1890. pTracker->SendBuffer.pDgramHdr = NULL; // catch erroneous frees
  1891. pTracker->RemoteIpAddress = pSrcIpDeviceContext->IpAddress;
  1892. pTracker->TransactionId = 0;
  1893. // Primary Wins ...
  1894. pTracker->Flags = NBT_NAME_SERVER | NBT_USE_UNIQUE_ADDR;
  1895. pTracker->RefCount = 2;
  1896. status = UdpSendNSBcast(pNameAddr,NbtConfig.pScope,pTracker,
  1897. NULL, NULL, NULL, 0, 0, eNAME_RELEASE, TRUE);
  1898. // Secondary Wins ...
  1899. pTracker->Flags = NBT_NAME_SERVER_BACKUP | NBT_USE_UNIQUE_ADDR;
  1900. pTracker->RefCount = 2;
  1901. status = UdpSendNSBcast(pNameAddr,NbtConfig.pScope,pTracker,
  1902. NULL, NULL, NULL, 0, 0, eNAME_RELEASE, TRUE);
  1903. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1904. pEntry2 = pRelDeviceContext->Linkage.Flink;
  1905. NBT_DEREFERENCE_DEVICE (pRelDeviceContext, REF_DEV_REREG, TRUE);
  1906. }
  1907. pEntry1 = pSrcIpDeviceContext->Linkage.Flink;
  1908. NBT_DEREFERENCE_DEVICE (pSrcIpDeviceContext, REF_DEV_REREG, TRUE);
  1909. }
  1910. }
  1911. pNameAddr->RefreshMask &= ReRegisterMask;
  1912. pNameAddr->Ttl = NbtConfig.InitialRefreshTimeout;
  1913. pEntry = pNameAddr->Linkage.Flink;
  1914. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_RELEASE_REFRESH, TRUE);
  1915. }
  1916. }
  1917. if (pTracker)
  1918. {
  1919. FreeTracker(pTracker, RELINK_TRACKER);
  1920. }
  1921. // start a refresh if there isn't one currently going on
  1922. // Note that there is a time window here that if the refresh is
  1923. // currently going on then, some names will not get refreshed with
  1924. // the new IpAddress right away, but have to wait to the next
  1925. // refresh interval. It seems that this is a rather unlikely
  1926. // scenario and given the low probability of DHCP changing the
  1927. // address it makes even less sense to add the code to handle that
  1928. // case.
  1929. //
  1930. if (NT_SUCCESS(CTEQueueForNonDispProcessing (DelayedRefreshBegin, NULL, NULL, NULL, NULL, TRUE)))
  1931. {
  1932. NbtConfig.GlobalRefreshState |= NBT_G_REFRESHING_NOW;
  1933. }
  1934. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1935. return(STATUS_SUCCESS);
  1936. }
  1937. //----------------------------------------------------------------------------
  1938. VOID
  1939. NbtStopRefreshTimer(
  1940. )
  1941. {
  1942. tTIMERQENTRY *pTimerEntry;
  1943. CTELockHandle OldIrq;
  1944. //
  1945. // Stop the regular Refresh Timer
  1946. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1947. if (pTimerEntry = NbtConfig.pRefreshTimer)
  1948. {
  1949. NbtConfig.pRefreshTimer = NULL;
  1950. StopTimer (pTimerEntry, NULL, NULL);
  1951. }
  1952. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1953. }
  1954. //----------------------------------------------------------------------------
  1955. NTSTATUS
  1956. strnlen(
  1957. PUCHAR pSrcString,
  1958. LONG MaxBufferLength,
  1959. LONG *pStringLen
  1960. )
  1961. {
  1962. LONG iIndex = 0;
  1963. while ((iIndex < MaxBufferLength-1) && (*pSrcString))
  1964. {
  1965. iIndex++;
  1966. pSrcString++;
  1967. }
  1968. if (*pSrcString)
  1969. {
  1970. ASSERT(0);
  1971. *pStringLen = 0;
  1972. return (STATUS_UNSUCCESSFUL);
  1973. }
  1974. *pStringLen = iIndex;
  1975. return (STATUS_SUCCESS);
  1976. }